cpp-pd-code-simplify-interface 0.1.11__py3-none-any.whl → 0.1.12__py3-none-any.whl
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/_worker.py +47 -0
- cpp_pd_code_simplify_interface/data/include/pdcode_simplify/pdcode_simplify.hpp +6 -0
- cpp_pd_code_simplify_interface/data/src/native_interface.cpp +4 -1
- cpp_pd_code_simplify_interface/data/src/pdcode_simplify.cpp +209 -110
- cpp_pd_code_simplify_interface/main.py +130 -11
- {cpp_pd_code_simplify_interface-0.1.11.dist-info → cpp_pd_code_simplify_interface-0.1.12.dist-info}/METADATA +9 -3
- cpp_pd_code_simplify_interface-0.1.12.dist-info/RECORD +12 -0
- cpp_pd_code_simplify_interface-0.1.11.dist-info/RECORD +0 -11
- {cpp_pd_code_simplify_interface-0.1.11.dist-info → cpp_pd_code_simplify_interface-0.1.12.dist-info}/WHEEL +0 -0
- {cpp_pd_code_simplify_interface-0.1.11.dist-info → cpp_pd_code_simplify_interface-0.1.12.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from .main import _run_one_direct
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main() -> int:
|
|
11
|
+
try:
|
|
12
|
+
request: dict[str, Any] = json.loads(sys.stdin.read())
|
|
13
|
+
result = _run_one_direct(
|
|
14
|
+
str(request.get("pd_text", "")),
|
|
15
|
+
max_paths=int(request.get("max_paths", -1)),
|
|
16
|
+
ban_heuristic=bool(request.get("ban_heuristic", False)),
|
|
17
|
+
reduction_round=int(request.get("reduction_round", -1)),
|
|
18
|
+
max_thread=int(request.get("max_thread", -1)),
|
|
19
|
+
timeout=int(request.get("timeout", -1)),
|
|
20
|
+
verbose=bool(request.get("verbose", False)),
|
|
21
|
+
known_crossingless_components=int(
|
|
22
|
+
request.get("known_crossingless_components", 0)
|
|
23
|
+
),
|
|
24
|
+
remove_crossings=request.get("remove_crossings") or [],
|
|
25
|
+
)
|
|
26
|
+
print(json.dumps({"ok": True, "result": result}, separators=(",", ":")))
|
|
27
|
+
return 0
|
|
28
|
+
except KeyboardInterrupt:
|
|
29
|
+
print(
|
|
30
|
+
json.dumps(
|
|
31
|
+
{"ok": False, "error": "interrupted by Ctrl+C"},
|
|
32
|
+
separators=(",", ":"),
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
return 130
|
|
36
|
+
except BaseException as exc: # noqa: BLE001 - return errors through JSON.
|
|
37
|
+
print(
|
|
38
|
+
json.dumps(
|
|
39
|
+
{"ok": False, "error": str(exc)},
|
|
40
|
+
separators=(",", ":"),
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
return 0
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
raise SystemExit(main())
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include <array>
|
|
4
|
+
#include <chrono>
|
|
4
5
|
#include <cstddef>
|
|
5
6
|
#include <functional>
|
|
6
7
|
#include <iosfwd>
|
|
@@ -51,10 +52,14 @@ struct GreenCrossing {
|
|
|
51
52
|
struct SimplifierOptions {
|
|
52
53
|
int max_paths = -1;
|
|
53
54
|
int max_threads = -1;
|
|
55
|
+
int timeout_seconds = -1;
|
|
56
|
+
bool has_timeout_deadline = false;
|
|
57
|
+
std::chrono::steady_clock::time_point timeout_deadline{};
|
|
54
58
|
bool ban_heuristic = false;
|
|
55
59
|
bool require_applicable = false;
|
|
56
60
|
bool verbose = false;
|
|
57
61
|
std::function<void(const std::string&)> progress;
|
|
62
|
+
std::function<bool()> should_cancel;
|
|
58
63
|
};
|
|
59
64
|
|
|
60
65
|
struct LinkComponentSummary {
|
|
@@ -121,6 +126,7 @@ struct ReductionResult {
|
|
|
121
126
|
std::size_t tested_green_paths = 0;
|
|
122
127
|
std::string last_path_search_mode;
|
|
123
128
|
bool stopped_by_round_limit = false;
|
|
129
|
+
bool timed_out = false;
|
|
124
130
|
};
|
|
125
131
|
|
|
126
132
|
PDCODE_SIMPLIFY_API PDCode parse_pd_code(const std::string& text);
|
|
@@ -106,7 +106,8 @@ std::string result_to_json(
|
|
|
106
106
|
out << "\"tested_green_paths\":" << result.tested_green_paths << ",";
|
|
107
107
|
out << "\"last_path_search_mode\":\"" << json_escape(result.last_path_search_mode) << "\",";
|
|
108
108
|
out << "\"stopped_by_round_limit\":"
|
|
109
|
-
<< (result.stopped_by_round_limit ? "true" : "false");
|
|
109
|
+
<< (result.stopped_by_round_limit ? "true" : "false") << ",";
|
|
110
|
+
out << "\"timed_out\":" << (result.timed_out ? "true" : "false");
|
|
110
111
|
out << "}";
|
|
111
112
|
return out.str();
|
|
112
113
|
}
|
|
@@ -133,6 +134,7 @@ char* pdcode_simplify_run_json(
|
|
|
133
134
|
int ban_heuristic,
|
|
134
135
|
int reduction_round,
|
|
135
136
|
int max_thread,
|
|
137
|
+
int timeout_seconds,
|
|
136
138
|
int verbose,
|
|
137
139
|
unsigned long long known_crossingless_components,
|
|
138
140
|
const int* removed_crossings,
|
|
@@ -146,6 +148,7 @@ char* pdcode_simplify_run_json(
|
|
|
146
148
|
pdcode_simplify::SimplifierOptions options;
|
|
147
149
|
options.max_paths = max_paths;
|
|
148
150
|
options.max_threads = max_thread;
|
|
151
|
+
options.timeout_seconds = timeout_seconds;
|
|
149
152
|
options.ban_heuristic = ban_heuristic != 0;
|
|
150
153
|
options.verbose = verbose != 0;
|
|
151
154
|
options.progress = [](const std::string& message) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#include "pdcode_simplify/pdcode_simplify.hpp"
|
|
2
2
|
|
|
3
3
|
#include <algorithm>
|
|
4
|
+
#include <chrono>
|
|
4
5
|
#include <cctype>
|
|
5
6
|
#include <cstdlib>
|
|
6
7
|
#include <deque>
|
|
@@ -987,7 +988,10 @@ std::set<int> normalized_removed_crossings(const PDCode& code, const std::vector
|
|
|
987
988
|
std::vector<int> heuristic_distances_to_target(
|
|
988
989
|
const DualGraph& graph,
|
|
989
990
|
int target,
|
|
990
|
-
int cutoff
|
|
991
|
+
int cutoff,
|
|
992
|
+
const SimplifierOptions& options);
|
|
993
|
+
|
|
994
|
+
void check_timeout(const SimplifierOptions& options);
|
|
991
995
|
|
|
992
996
|
void collect_simple_paths_dfs(
|
|
993
997
|
const DualGraph& graph,
|
|
@@ -999,7 +1003,9 @@ void collect_simple_paths_dfs(
|
|
|
999
1003
|
const std::vector<int>& distance,
|
|
1000
1004
|
std::vector<char>& visited,
|
|
1001
1005
|
std::vector<int>& current_path,
|
|
1002
|
-
std::vector<std::vector<int>>& paths
|
|
1006
|
+
std::vector<std::vector<int>>& paths,
|
|
1007
|
+
const SimplifierOptions& options) {
|
|
1008
|
+
check_timeout(options);
|
|
1003
1009
|
const int infinity = std::numeric_limits<int>::max() / 4;
|
|
1004
1010
|
if (static_cast<int>(current_path.size()) - 1 >= cutoff) {
|
|
1005
1011
|
return;
|
|
@@ -1045,7 +1051,8 @@ void collect_simple_paths_dfs(
|
|
|
1045
1051
|
distance,
|
|
1046
1052
|
visited,
|
|
1047
1053
|
current_path,
|
|
1048
|
-
paths
|
|
1054
|
+
paths,
|
|
1055
|
+
options);
|
|
1049
1056
|
if (max_paths != -1 && static_cast<int>(paths.size()) > max_paths) {
|
|
1050
1057
|
visited[next] = false;
|
|
1051
1058
|
current_path.pop_back();
|
|
@@ -1063,7 +1070,9 @@ std::vector<std::vector<int>> collect_simple_paths(
|
|
|
1063
1070
|
int source,
|
|
1064
1071
|
int target,
|
|
1065
1072
|
int cutoff,
|
|
1066
|
-
int max_paths
|
|
1073
|
+
int max_paths,
|
|
1074
|
+
const SimplifierOptions& options) {
|
|
1075
|
+
check_timeout(options);
|
|
1067
1076
|
std::vector<std::vector<int>> paths;
|
|
1068
1077
|
if (source == target || source < 0 || target < 0 ||
|
|
1069
1078
|
source >= static_cast<int>(graph.faces.size()) ||
|
|
@@ -1074,7 +1083,7 @@ std::vector<std::vector<int>> collect_simple_paths(
|
|
|
1074
1083
|
|
|
1075
1084
|
std::vector<char> visited(graph.faces.size(), false);
|
|
1076
1085
|
std::vector<int> current_path{source};
|
|
1077
|
-
const std::vector<int> distance = heuristic_distances_to_target(graph, target, cutoff);
|
|
1086
|
+
const std::vector<int> distance = heuristic_distances_to_target(graph, target, cutoff, options);
|
|
1078
1087
|
visited[source] = true;
|
|
1079
1088
|
collect_simple_paths_dfs(
|
|
1080
1089
|
graph,
|
|
@@ -1086,14 +1095,16 @@ std::vector<std::vector<int>> collect_simple_paths(
|
|
|
1086
1095
|
distance,
|
|
1087
1096
|
visited,
|
|
1088
1097
|
current_path,
|
|
1089
|
-
paths
|
|
1098
|
+
paths,
|
|
1099
|
+
options);
|
|
1090
1100
|
return paths;
|
|
1091
1101
|
}
|
|
1092
1102
|
|
|
1093
1103
|
std::vector<int> heuristic_distances_to_target(
|
|
1094
1104
|
const DualGraph& graph,
|
|
1095
1105
|
int target,
|
|
1096
|
-
int cutoff
|
|
1106
|
+
int cutoff,
|
|
1107
|
+
const SimplifierOptions& options) {
|
|
1097
1108
|
const int face_count = static_cast<int>(graph.faces.size());
|
|
1098
1109
|
const int infinity = std::numeric_limits<int>::max() / 4;
|
|
1099
1110
|
std::vector<int> distance(face_count, infinity);
|
|
@@ -1102,6 +1113,7 @@ std::vector<int> heuristic_distances_to_target(
|
|
|
1102
1113
|
queue.push_back(target);
|
|
1103
1114
|
|
|
1104
1115
|
while (!queue.empty()) {
|
|
1116
|
+
check_timeout(options);
|
|
1105
1117
|
const int current = queue.front();
|
|
1106
1118
|
queue.pop_front();
|
|
1107
1119
|
for (int edge_index : graph.adjacency[current]) {
|
|
@@ -1179,7 +1191,9 @@ std::vector<std::vector<int>> collect_heuristic_paths(
|
|
|
1179
1191
|
const DualGraph& graph,
|
|
1180
1192
|
int source,
|
|
1181
1193
|
int target,
|
|
1182
|
-
int cutoff
|
|
1194
|
+
int cutoff,
|
|
1195
|
+
const SimplifierOptions& options) {
|
|
1196
|
+
check_timeout(options);
|
|
1183
1197
|
std::vector<std::vector<int>> paths;
|
|
1184
1198
|
const int face_count = static_cast<int>(graph.faces.size());
|
|
1185
1199
|
if (source == target || source < 0 || target < 0 ||
|
|
@@ -1187,7 +1201,7 @@ std::vector<std::vector<int>> collect_heuristic_paths(
|
|
|
1187
1201
|
return paths;
|
|
1188
1202
|
}
|
|
1189
1203
|
|
|
1190
|
-
const std::vector<int> distance = heuristic_distances_to_target(graph, target, cutoff);
|
|
1204
|
+
const std::vector<int> distance = heuristic_distances_to_target(graph, target, cutoff, options);
|
|
1191
1205
|
const int infinity = std::numeric_limits<int>::max() / 4;
|
|
1192
1206
|
if (distance[source] == infinity || distance[source] >= cutoff) {
|
|
1193
1207
|
return paths;
|
|
@@ -1215,6 +1229,7 @@ std::vector<std::vector<int>> collect_heuristic_paths(
|
|
|
1215
1229
|
int popped_states = 0;
|
|
1216
1230
|
while (!queue.empty() && popped_states < state_budget &&
|
|
1217
1231
|
static_cast<int>(paths.size()) < path_budget) {
|
|
1232
|
+
check_timeout(options);
|
|
1218
1233
|
HeuristicState state = queue.top();
|
|
1219
1234
|
queue.pop();
|
|
1220
1235
|
++popped_states;
|
|
@@ -1823,6 +1838,41 @@ std::string search_mode_for_options(const SimplifierOptions& options) {
|
|
|
1823
1838
|
return "bounded";
|
|
1824
1839
|
}
|
|
1825
1840
|
|
|
1841
|
+
void validate_timeout_options(const SimplifierOptions& options) {
|
|
1842
|
+
if (options.timeout_seconds < -1 || options.timeout_seconds == 0) {
|
|
1843
|
+
throw std::invalid_argument("timeout must be -1 or a positive integer");
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
class TimeoutError : public std::runtime_error {
|
|
1848
|
+
public:
|
|
1849
|
+
explicit TimeoutError(const std::string& message) : std::runtime_error(message) {}
|
|
1850
|
+
};
|
|
1851
|
+
|
|
1852
|
+
SimplifierOptions with_timeout_deadline(SimplifierOptions options) {
|
|
1853
|
+
validate_timeout_options(options);
|
|
1854
|
+
if (options.timeout_seconds > 0 && !options.has_timeout_deadline) {
|
|
1855
|
+
options.has_timeout_deadline = true;
|
|
1856
|
+
options.timeout_deadline =
|
|
1857
|
+
std::chrono::steady_clock::now() + std::chrono::seconds(options.timeout_seconds);
|
|
1858
|
+
}
|
|
1859
|
+
return options;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
void check_timeout(const SimplifierOptions& options) {
|
|
1863
|
+
if (options.should_cancel && options.should_cancel()) {
|
|
1864
|
+
throw std::runtime_error("interrupted by Ctrl+C");
|
|
1865
|
+
}
|
|
1866
|
+
if (!options.has_timeout_deadline) {
|
|
1867
|
+
return;
|
|
1868
|
+
}
|
|
1869
|
+
if (std::chrono::steady_clock::now() >= options.timeout_deadline) {
|
|
1870
|
+
std::ostringstream message;
|
|
1871
|
+
message << "timeout after " << options.timeout_seconds << " seconds";
|
|
1872
|
+
throw TimeoutError(message.str());
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1826
1876
|
} // namespace
|
|
1827
1877
|
|
|
1828
1878
|
PDCode parse_pd_code(const std::string& text) {
|
|
@@ -2213,6 +2263,7 @@ RedPathSearchOutcome search_single_red_path(
|
|
|
2213
2263
|
const std::string& path_search_mode,
|
|
2214
2264
|
int red_index,
|
|
2215
2265
|
const std::atomic<int>* best_found_index) {
|
|
2266
|
+
check_timeout(options);
|
|
2216
2267
|
RedPathSearchOutcome outcome;
|
|
2217
2268
|
outcome.witness.path_search_mode = path_search_mode;
|
|
2218
2269
|
if (should_skip_parallel_red_path(red_index, best_found_index)) {
|
|
@@ -2231,6 +2282,7 @@ RedPathSearchOutcome search_single_red_path(
|
|
|
2231
2282
|
const std::array<int, 2> destinations{end_face, end_opposite_face};
|
|
2232
2283
|
|
|
2233
2284
|
for (std::size_t i = 1; i + 1 < red_path.size(); ++i) {
|
|
2285
|
+
check_timeout(options);
|
|
2234
2286
|
const Endpoint endpoint = red_path[i];
|
|
2235
2287
|
const int right_region = graph.edge_to_face[endpoint_key(endpoint)];
|
|
2236
2288
|
const int left_region = graph.edge_to_face[endpoint_key(diagram.opposite(endpoint))];
|
|
@@ -2243,15 +2295,17 @@ RedPathSearchOutcome search_single_red_path(
|
|
|
2243
2295
|
const int cutoff = static_cast<int>(red_path.size()) - 1;
|
|
2244
2296
|
for (int source : sources) {
|
|
2245
2297
|
for (int destination : destinations) {
|
|
2298
|
+
check_timeout(options);
|
|
2246
2299
|
if (should_skip_parallel_red_path(red_index, best_found_index)) {
|
|
2247
2300
|
outcome.skipped = true;
|
|
2248
2301
|
return outcome;
|
|
2249
2302
|
}
|
|
2250
2303
|
std::vector<std::vector<int>> found_paths;
|
|
2251
2304
|
if (options.max_paths == -1 && !options.ban_heuristic) {
|
|
2252
|
-
found_paths = collect_heuristic_paths(graph, source, destination, cutoff);
|
|
2305
|
+
found_paths = collect_heuristic_paths(graph, source, destination, cutoff, options);
|
|
2253
2306
|
} else {
|
|
2254
|
-
found_paths = collect_simple_paths(
|
|
2307
|
+
found_paths = collect_simple_paths(
|
|
2308
|
+
graph, source, destination, cutoff, options.max_paths, options);
|
|
2255
2309
|
}
|
|
2256
2310
|
paths.insert(paths.end(), found_paths.begin(), found_paths.end());
|
|
2257
2311
|
if (options.max_paths != -1 && static_cast<int>(paths.size()) > options.max_paths) {
|
|
@@ -2261,6 +2315,7 @@ RedPathSearchOutcome search_single_red_path(
|
|
|
2261
2315
|
}
|
|
2262
2316
|
|
|
2263
2317
|
for (const auto& green_path : paths) {
|
|
2318
|
+
check_timeout(options);
|
|
2264
2319
|
if (should_skip_parallel_red_path(red_index, best_found_index)) {
|
|
2265
2320
|
outcome.skipped = true;
|
|
2266
2321
|
return outcome;
|
|
@@ -2401,36 +2456,49 @@ SimplificationResult find_simplification_parallel_bruteforce(
|
|
|
2401
2456
|
SimplificationResult find_simplification(
|
|
2402
2457
|
const PDCode& code,
|
|
2403
2458
|
const SimplifierOptions& options) {
|
|
2459
|
+
const SimplifierOptions run_options = with_timeout_deadline(options);
|
|
2460
|
+
check_timeout(run_options);
|
|
2404
2461
|
SimplificationResult result;
|
|
2405
|
-
result.path_search_mode = search_mode_for_options(
|
|
2462
|
+
result.path_search_mode = search_mode_for_options(run_options);
|
|
2406
2463
|
Diagram diagram(code);
|
|
2464
|
+
check_timeout(run_options);
|
|
2407
2465
|
DualGraph base_graph(diagram);
|
|
2466
|
+
check_timeout(run_options);
|
|
2408
2467
|
const auto red_lines = possible_red_lines(diagram);
|
|
2409
|
-
|
|
2468
|
+
check_timeout(run_options);
|
|
2469
|
+
const bool brute_force_mode = run_options.max_paths == -1 && run_options.ban_heuristic;
|
|
2410
2470
|
const int worker_count = brute_force_mode
|
|
2411
2471
|
? selected_bruteforce_worker_count(
|
|
2412
|
-
|
|
2472
|
+
run_options.max_threads,
|
|
2413
2473
|
static_cast<int>(red_lines.size()))
|
|
2414
2474
|
: 1;
|
|
2475
|
+
if (brute_force_mode && run_options.max_threads == -1) {
|
|
2476
|
+
std::ostringstream message;
|
|
2477
|
+
message << "bruteforce_threads max_thread=-1"
|
|
2478
|
+
<< " actual_threads=" << worker_count
|
|
2479
|
+
<< " red_paths=" << red_lines.size();
|
|
2480
|
+
emit_progress(run_options, message.str());
|
|
2481
|
+
}
|
|
2415
2482
|
if (worker_count > 1) {
|
|
2416
2483
|
return find_simplification_parallel_bruteforce(
|
|
2417
2484
|
code,
|
|
2418
2485
|
diagram,
|
|
2419
2486
|
base_graph,
|
|
2420
2487
|
red_lines,
|
|
2421
|
-
|
|
2488
|
+
run_options,
|
|
2422
2489
|
result.path_search_mode,
|
|
2423
2490
|
worker_count);
|
|
2424
2491
|
}
|
|
2425
2492
|
|
|
2426
2493
|
for (const auto& red_path : red_lines) {
|
|
2494
|
+
check_timeout(run_options);
|
|
2427
2495
|
++result.tested_red_paths;
|
|
2428
2496
|
const RedPathSearchOutcome outcome = search_single_red_path(
|
|
2429
2497
|
code,
|
|
2430
2498
|
diagram,
|
|
2431
2499
|
base_graph,
|
|
2432
2500
|
red_path,
|
|
2433
|
-
|
|
2501
|
+
run_options,
|
|
2434
2502
|
result.path_search_mode,
|
|
2435
2503
|
-1,
|
|
2436
2504
|
nullptr);
|
|
@@ -2452,125 +2520,155 @@ ReductionResult reduce_pd_code(
|
|
|
2452
2520
|
std::size_t known_crossingless_components,
|
|
2453
2521
|
const SimplifierOptions& options,
|
|
2454
2522
|
int reduction_round) {
|
|
2455
|
-
|
|
2456
|
-
std::ostringstream message;
|
|
2457
|
-
message << "start input_crossings=" << code.size()
|
|
2458
|
-
<< " known_crossingless_components=" << known_crossingless_components
|
|
2459
|
-
<< " reduction_round=" << reduction_round
|
|
2460
|
-
<< " max_paths=" << options.max_paths
|
|
2461
|
-
<< " max_thread=" << options.max_threads
|
|
2462
|
-
<< " heuristic=" << (options.ban_heuristic ? "off" : "on");
|
|
2463
|
-
emit_progress(options, message.str());
|
|
2464
|
-
}
|
|
2465
|
-
|
|
2466
|
-
const PDSimplificationResult prepared = simplify_pd_code(code, known_crossingless_components);
|
|
2523
|
+
const SimplifierOptions run_options = with_timeout_deadline(options);
|
|
2467
2524
|
ReductionResult output;
|
|
2468
|
-
output.code =
|
|
2469
|
-
output.crossingless_components =
|
|
2470
|
-
output.reidemeister_i_moves = prepared.reidemeister_i_moves;
|
|
2471
|
-
output.nugatory_crossing_moves = prepared.nugatory_crossing_moves;
|
|
2472
|
-
{
|
|
2473
|
-
std::ostringstream message;
|
|
2474
|
-
message << "pre_simplify input_crossings=" << code.size()
|
|
2475
|
-
<< " output_crossings=" << output.code.size()
|
|
2476
|
-
<< " crossingless_components=" << output.crossingless_components
|
|
2477
|
-
<< " r1_moves=" << prepared.reidemeister_i_moves
|
|
2478
|
-
<< " nugatory_moves=" << prepared.nugatory_crossing_moves;
|
|
2479
|
-
emit_progress(options, message.str());
|
|
2480
|
-
}
|
|
2525
|
+
output.code = code;
|
|
2526
|
+
output.crossingless_components = known_crossingless_components;
|
|
2481
2527
|
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
search_options.require_applicable = true;
|
|
2485
|
-
const int round = output.mid_simplification_rounds + 1;
|
|
2528
|
+
try {
|
|
2529
|
+
check_timeout(run_options);
|
|
2486
2530
|
{
|
|
2487
2531
|
std::ostringstream message;
|
|
2488
|
-
message << "
|
|
2489
|
-
<< "
|
|
2490
|
-
<< "
|
|
2491
|
-
<< "
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2532
|
+
message << "start input_crossings=" << code.size()
|
|
2533
|
+
<< " known_crossingless_components=" << known_crossingless_components
|
|
2534
|
+
<< " reduction_round=" << reduction_round
|
|
2535
|
+
<< " max_paths=" << run_options.max_paths
|
|
2536
|
+
<< " max_thread=" << run_options.max_threads
|
|
2537
|
+
<< " timeout=" << run_options.timeout_seconds
|
|
2538
|
+
<< " heuristic=" << (run_options.ban_heuristic ? "off" : "on");
|
|
2539
|
+
emit_progress(run_options, message.str());
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
const PDSimplificationResult prepared =
|
|
2543
|
+
simplify_pd_code(code, known_crossingless_components);
|
|
2544
|
+
output.code = prepared.code;
|
|
2545
|
+
output.crossingless_components = prepared.crossingless_components;
|
|
2546
|
+
output.reidemeister_i_moves = prepared.reidemeister_i_moves;
|
|
2547
|
+
output.nugatory_crossing_moves = prepared.nugatory_crossing_moves;
|
|
2548
|
+
check_timeout(run_options);
|
|
2498
2549
|
{
|
|
2499
2550
|
std::ostringstream message;
|
|
2500
|
-
message << "
|
|
2501
|
-
<< "
|
|
2502
|
-
<< "
|
|
2503
|
-
<< "
|
|
2504
|
-
<< "
|
|
2505
|
-
emit_progress(
|
|
2506
|
-
}
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
SimplifierOptions
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2551
|
+
message << "pre_simplify input_crossings=" << code.size()
|
|
2552
|
+
<< " output_crossings=" << output.code.size()
|
|
2553
|
+
<< " crossingless_components=" << output.crossingless_components
|
|
2554
|
+
<< " r1_moves=" << prepared.reidemeister_i_moves
|
|
2555
|
+
<< " nugatory_moves=" << prepared.nugatory_crossing_moves;
|
|
2556
|
+
emit_progress(run_options, message.str());
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
while (reduction_round < 0 || output.mid_simplification_rounds < reduction_round) {
|
|
2560
|
+
check_timeout(run_options);
|
|
2561
|
+
SimplifierOptions search_options = run_options;
|
|
2562
|
+
search_options.require_applicable = true;
|
|
2563
|
+
output.last_path_search_mode = search_mode_for_options(search_options);
|
|
2564
|
+
const int round = output.mid_simplification_rounds + 1;
|
|
2514
2565
|
{
|
|
2515
2566
|
std::ostringstream message;
|
|
2516
2567
|
message << "round " << round
|
|
2517
|
-
<< "
|
|
2518
|
-
<< "
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
output.
|
|
2523
|
-
output.
|
|
2524
|
-
output.
|
|
2568
|
+
<< " search_start crossings=" << output.code.size()
|
|
2569
|
+
<< " mode=" << output.last_path_search_mode
|
|
2570
|
+
<< " max_thread=" << search_options.max_threads;
|
|
2571
|
+
emit_progress(run_options, message.str());
|
|
2572
|
+
}
|
|
2573
|
+
SimplificationResult search = find_simplification(output.code, search_options);
|
|
2574
|
+
output.tested_red_paths += search.tested_red_paths;
|
|
2575
|
+
output.tested_green_paths += search.tested_green_paths;
|
|
2576
|
+
output.last_path_search_mode = search.path_search_mode;
|
|
2525
2577
|
{
|
|
2526
2578
|
std::ostringstream message;
|
|
2527
2579
|
message << "round " << round
|
|
2528
|
-
<< "
|
|
2529
|
-
<< "
|
|
2530
|
-
<< "
|
|
2531
|
-
|
|
2580
|
+
<< " search_done found=" << (search.found ? "yes" : "no")
|
|
2581
|
+
<< " mode=" << search.path_search_mode
|
|
2582
|
+
<< " tested_red=" << search.tested_red_paths
|
|
2583
|
+
<< " tested_green=" << search.tested_green_paths;
|
|
2584
|
+
emit_progress(run_options, message.str());
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
if (!search.found && reduction_round < 0 &&
|
|
2588
|
+
run_options.max_paths == -1 && !run_options.ban_heuristic) {
|
|
2589
|
+
SimplifierOptions brute_options = run_options;
|
|
2590
|
+
brute_options.max_paths = -1;
|
|
2591
|
+
brute_options.ban_heuristic = true;
|
|
2592
|
+
brute_options.require_applicable = true;
|
|
2593
|
+
output.last_path_search_mode = search_mode_for_options(brute_options);
|
|
2594
|
+
{
|
|
2595
|
+
std::ostringstream message;
|
|
2596
|
+
message << "round " << round
|
|
2597
|
+
<< " brute_fallback_start crossings=" << output.code.size()
|
|
2598
|
+
<< " max_thread=" << brute_options.max_threads;
|
|
2599
|
+
emit_progress(run_options, message.str());
|
|
2600
|
+
}
|
|
2601
|
+
SimplificationResult brute = find_simplification(output.code, brute_options);
|
|
2602
|
+
output.tested_red_paths += brute.tested_red_paths;
|
|
2603
|
+
output.tested_green_paths += brute.tested_green_paths;
|
|
2604
|
+
output.last_path_search_mode = brute.path_search_mode;
|
|
2605
|
+
{
|
|
2606
|
+
std::ostringstream message;
|
|
2607
|
+
message << "round " << round
|
|
2608
|
+
<< " brute_fallback_done found=" << (brute.found ? "yes" : "no")
|
|
2609
|
+
<< " tested_red=" << brute.tested_red_paths
|
|
2610
|
+
<< " tested_green=" << brute.tested_green_paths;
|
|
2611
|
+
emit_progress(run_options, message.str());
|
|
2612
|
+
}
|
|
2613
|
+
if (brute.found) {
|
|
2614
|
+
++output.heuristic_failover_rounds;
|
|
2615
|
+
search = std::move(brute);
|
|
2616
|
+
}
|
|
2532
2617
|
}
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2618
|
+
|
|
2619
|
+
if (!search.found) {
|
|
2620
|
+
{
|
|
2621
|
+
std::ostringstream message;
|
|
2622
|
+
message << "round " << round
|
|
2623
|
+
<< " stop_no_path crossings=" << output.code.size();
|
|
2624
|
+
emit_progress(run_options, message.str());
|
|
2625
|
+
}
|
|
2626
|
+
break;
|
|
2536
2627
|
}
|
|
2537
|
-
}
|
|
2538
2628
|
|
|
2539
|
-
|
|
2629
|
+
const std::size_t before_apply_crossings = output.code.size();
|
|
2630
|
+
check_timeout(run_options);
|
|
2631
|
+
const MidSimplificationApplyResult applied =
|
|
2632
|
+
apply_simplification_witness(output.code, search, output.crossingless_components);
|
|
2633
|
+
++output.mid_simplification_rounds;
|
|
2634
|
+
output.code = applied.code;
|
|
2635
|
+
output.crossingless_components = applied.crossingless_components;
|
|
2636
|
+
check_timeout(run_options);
|
|
2637
|
+
const PDSimplificationResult simplified =
|
|
2638
|
+
simplify_pd_code(output.code, output.crossingless_components);
|
|
2639
|
+
output.code = simplified.code;
|
|
2640
|
+
output.crossingless_components = simplified.crossingless_components;
|
|
2641
|
+
output.reidemeister_i_moves += simplified.reidemeister_i_moves;
|
|
2642
|
+
output.nugatory_crossing_moves += simplified.nugatory_crossing_moves;
|
|
2643
|
+
check_timeout(run_options);
|
|
2540
2644
|
{
|
|
2541
2645
|
std::ostringstream message;
|
|
2542
2646
|
message << "round " << round
|
|
2543
|
-
<< "
|
|
2544
|
-
|
|
2647
|
+
<< " applied crossings=" << before_apply_crossings
|
|
2648
|
+
<< " -> " << applied.code.size()
|
|
2649
|
+
<< " -> " << output.code.size()
|
|
2650
|
+
<< " crossingless_components=" << output.crossingless_components
|
|
2651
|
+
<< " r1_moves=" << simplified.reidemeister_i_moves
|
|
2652
|
+
<< " nugatory_moves=" << simplified.nugatory_crossing_moves;
|
|
2653
|
+
emit_progress(run_options, message.str());
|
|
2545
2654
|
}
|
|
2546
|
-
break;
|
|
2547
2655
|
}
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
const MidSimplificationApplyResult applied =
|
|
2551
|
-
apply_simplification_witness(output.code, search, output.crossingless_components);
|
|
2552
|
-
++output.mid_simplification_rounds;
|
|
2553
|
-
const PDSimplificationResult simplified =
|
|
2554
|
-
simplify_pd_code(applied.code, applied.crossingless_components);
|
|
2555
|
-
output.code = simplified.code;
|
|
2556
|
-
output.crossingless_components = simplified.crossingless_components;
|
|
2557
|
-
output.reidemeister_i_moves += simplified.reidemeister_i_moves;
|
|
2558
|
-
output.nugatory_crossing_moves += simplified.nugatory_crossing_moves;
|
|
2656
|
+
} catch (const TimeoutError& error) {
|
|
2657
|
+
output.timed_out = true;
|
|
2559
2658
|
{
|
|
2560
2659
|
std::ostringstream message;
|
|
2561
|
-
message <<
|
|
2562
|
-
<< "
|
|
2563
|
-
<< " -> " << applied.code.size()
|
|
2564
|
-
<< " -> " << output.code.size()
|
|
2660
|
+
message << error.what()
|
|
2661
|
+
<< "; returning_current_best crossings=" << output.code.size()
|
|
2565
2662
|
<< " crossingless_components=" << output.crossingless_components
|
|
2566
|
-
<< "
|
|
2567
|
-
|
|
2568
|
-
emit_progress(options, message.str());
|
|
2663
|
+
<< " mid_rounds=" << output.mid_simplification_rounds;
|
|
2664
|
+
emit_progress(run_options, message.str());
|
|
2569
2665
|
}
|
|
2570
2666
|
}
|
|
2571
2667
|
|
|
2572
2668
|
output.stopped_by_round_limit =
|
|
2573
|
-
|
|
2669
|
+
!output.timed_out &&
|
|
2670
|
+
reduction_round >= 0 &&
|
|
2671
|
+
output.mid_simplification_rounds >= reduction_round;
|
|
2574
2672
|
{
|
|
2575
2673
|
std::ostringstream message;
|
|
2576
2674
|
message << "done final_crossings=" << output.code.size()
|
|
@@ -2578,8 +2676,9 @@ ReductionResult reduce_pd_code(
|
|
|
2578
2676
|
<< " mid_rounds=" << output.mid_simplification_rounds
|
|
2579
2677
|
<< " heuristic_failover_rounds=" << output.heuristic_failover_rounds
|
|
2580
2678
|
<< " stopped_by_round_limit="
|
|
2581
|
-
<< (output.stopped_by_round_limit ? "yes" : "no")
|
|
2582
|
-
|
|
2679
|
+
<< (output.stopped_by_round_limit ? "yes" : "no")
|
|
2680
|
+
<< " timed_out=" << (output.timed_out ? "yes" : "no");
|
|
2681
|
+
emit_progress(run_options, message.str());
|
|
2583
2682
|
}
|
|
2584
2683
|
return output;
|
|
2585
2684
|
}
|
|
@@ -762,6 +762,7 @@ def _load_library() -> ctypes.CDLL:
|
|
|
762
762
|
ctypes.c_int,
|
|
763
763
|
ctypes.c_int,
|
|
764
764
|
ctypes.c_int,
|
|
765
|
+
ctypes.c_int,
|
|
765
766
|
ctypes.c_ulonglong,
|
|
766
767
|
ctypes.POINTER(ctypes.c_int),
|
|
767
768
|
ctypes.c_ulonglong,
|
|
@@ -774,13 +775,14 @@ def _load_library() -> ctypes.CDLL:
|
|
|
774
775
|
return library
|
|
775
776
|
|
|
776
777
|
|
|
777
|
-
def
|
|
778
|
+
def _run_one_direct(
|
|
778
779
|
pd_text: str,
|
|
779
780
|
*,
|
|
780
781
|
max_paths: int = -1,
|
|
781
782
|
ban_heuristic: bool = False,
|
|
782
783
|
reduction_round: int = -1,
|
|
783
784
|
max_thread: int = -1,
|
|
785
|
+
timeout: int = -1,
|
|
784
786
|
verbose: bool = False,
|
|
785
787
|
known_crossingless_components: int = 0,
|
|
786
788
|
remove_crossings: Optional[Sequence[int]] = None,
|
|
@@ -789,6 +791,8 @@ def _run_one(
|
|
|
789
791
|
raise ValueError("reduction_round must be -1 or a non-negative integer")
|
|
790
792
|
if max_thread < -1 or max_thread == 0:
|
|
791
793
|
raise ValueError("max_thread must be -1 or a positive integer")
|
|
794
|
+
if timeout < -1 or timeout == 0:
|
|
795
|
+
raise ValueError("timeout must be -1 or a positive integer")
|
|
792
796
|
library = _load_library()
|
|
793
797
|
removed_count = 0 if remove_crossings is None else len(remove_crossings)
|
|
794
798
|
removed_array = None
|
|
@@ -801,6 +805,7 @@ def _run_one(
|
|
|
801
805
|
1 if ban_heuristic else 0,
|
|
802
806
|
int(reduction_round),
|
|
803
807
|
int(max_thread),
|
|
808
|
+
int(timeout),
|
|
804
809
|
1 if verbose else 0,
|
|
805
810
|
int(known_crossingless_components),
|
|
806
811
|
removed_array,
|
|
@@ -822,6 +827,93 @@ def _run_one(
|
|
|
822
827
|
return result
|
|
823
828
|
|
|
824
829
|
|
|
830
|
+
def _terminate_process(proc: subprocess.Popen[str]) -> None:
|
|
831
|
+
if proc.poll() is not None:
|
|
832
|
+
return
|
|
833
|
+
proc.terminate()
|
|
834
|
+
try:
|
|
835
|
+
proc.wait(timeout=2.0)
|
|
836
|
+
except subprocess.TimeoutExpired:
|
|
837
|
+
proc.kill()
|
|
838
|
+
proc.wait()
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def _run_one(
|
|
842
|
+
pd_text: str,
|
|
843
|
+
*,
|
|
844
|
+
max_paths: int = -1,
|
|
845
|
+
ban_heuristic: bool = False,
|
|
846
|
+
reduction_round: int = -1,
|
|
847
|
+
max_thread: int = -1,
|
|
848
|
+
timeout: int = -1,
|
|
849
|
+
verbose: bool = False,
|
|
850
|
+
known_crossingless_components: int = 0,
|
|
851
|
+
remove_crossings: Optional[Sequence[int]] = None,
|
|
852
|
+
) -> dict[str, Any]:
|
|
853
|
+
if reduction_round < -1:
|
|
854
|
+
raise ValueError("reduction_round must be -1 or a non-negative integer")
|
|
855
|
+
if max_thread < -1 or max_thread == 0:
|
|
856
|
+
raise ValueError("max_thread must be -1 or a positive integer")
|
|
857
|
+
if timeout < -1 or timeout == 0:
|
|
858
|
+
raise ValueError("timeout must be -1 or a positive integer")
|
|
859
|
+
|
|
860
|
+
request = {
|
|
861
|
+
"pd_text": pd_text,
|
|
862
|
+
"max_paths": int(max_paths),
|
|
863
|
+
"ban_heuristic": bool(ban_heuristic),
|
|
864
|
+
"reduction_round": int(reduction_round),
|
|
865
|
+
"max_thread": int(max_thread),
|
|
866
|
+
"timeout": int(timeout),
|
|
867
|
+
"verbose": bool(verbose),
|
|
868
|
+
"known_crossingless_components": int(known_crossingless_components),
|
|
869
|
+
"remove_crossings": [int(value) for value in remove_crossings or []],
|
|
870
|
+
}
|
|
871
|
+
env = os.environ.copy()
|
|
872
|
+
project_root = str(pathlib.Path(__file__).resolve().parents[1])
|
|
873
|
+
env["PYTHONPATH"] = project_root + os.pathsep + env.get("PYTHONPATH", "")
|
|
874
|
+
proc = subprocess.Popen(
|
|
875
|
+
[
|
|
876
|
+
sys.executable,
|
|
877
|
+
"-m",
|
|
878
|
+
"cpp_pd_code_simplify_interface._worker",
|
|
879
|
+
],
|
|
880
|
+
cwd=str(pathlib.Path.cwd()),
|
|
881
|
+
text=True,
|
|
882
|
+
stdin=subprocess.PIPE,
|
|
883
|
+
stdout=subprocess.PIPE,
|
|
884
|
+
stderr=None if verbose else subprocess.PIPE,
|
|
885
|
+
env=env,
|
|
886
|
+
)
|
|
887
|
+
try:
|
|
888
|
+
stdout, stderr = proc.communicate(json.dumps(request))
|
|
889
|
+
except KeyboardInterrupt:
|
|
890
|
+
_terminate_process(proc)
|
|
891
|
+
raise
|
|
892
|
+
|
|
893
|
+
if proc.returncode != 0:
|
|
894
|
+
detail = (stderr or "").strip()
|
|
895
|
+
raise PdCodeSimplifyInterfaceError(
|
|
896
|
+
f"C++ interface worker failed with exit code {proc.returncode}"
|
|
897
|
+
+ (f": {detail}" if detail else "")
|
|
898
|
+
)
|
|
899
|
+
try:
|
|
900
|
+
envelope = json.loads(stdout)
|
|
901
|
+
except json.JSONDecodeError as exc:
|
|
902
|
+
raise PdCodeSimplifyInterfaceError(
|
|
903
|
+
f"invalid interface worker JSON output: {stdout!r}"
|
|
904
|
+
) from exc
|
|
905
|
+
if not isinstance(envelope, dict):
|
|
906
|
+
raise PdCodeSimplifyInterfaceError(
|
|
907
|
+
f"invalid interface worker response type: {type(envelope)!r}"
|
|
908
|
+
)
|
|
909
|
+
if not envelope.get("ok", False):
|
|
910
|
+
raise PdCodeSimplifyInterfaceError(str(envelope.get("error", "unknown worker error")))
|
|
911
|
+
result = envelope.get("result")
|
|
912
|
+
if not isinstance(result, dict):
|
|
913
|
+
raise PdCodeSimplifyInterfaceError("interface worker did not return a JSON object result")
|
|
914
|
+
return result
|
|
915
|
+
|
|
916
|
+
|
|
825
917
|
def simplify(
|
|
826
918
|
pd_code: PdInput,
|
|
827
919
|
*,
|
|
@@ -829,6 +921,7 @@ def simplify(
|
|
|
829
921
|
ban_heuristic: bool = False,
|
|
830
922
|
reduction_round: int = -1,
|
|
831
923
|
max_thread: int = -1,
|
|
924
|
+
timeout: int = -1,
|
|
832
925
|
verbose: bool = False,
|
|
833
926
|
known_crossingless_components: int = 0,
|
|
834
927
|
remove_crossings: Optional[Sequence[int]] = None,
|
|
@@ -841,6 +934,7 @@ def simplify(
|
|
|
841
934
|
ban_heuristic=ban_heuristic,
|
|
842
935
|
reduction_round=reduction_round,
|
|
843
936
|
max_thread=max_thread,
|
|
937
|
+
timeout=timeout,
|
|
844
938
|
verbose=verbose,
|
|
845
939
|
known_crossingless_components=known_crossingless_components,
|
|
846
940
|
remove_crossings=remove_crossings,
|
|
@@ -854,6 +948,7 @@ def simplify_many(
|
|
|
854
948
|
ban_heuristic: bool = False,
|
|
855
949
|
reduction_round: int = -1,
|
|
856
950
|
max_thread: int = -1,
|
|
951
|
+
timeout: int = -1,
|
|
857
952
|
verbose: bool = False,
|
|
858
953
|
known_crossingless_components: int = 0,
|
|
859
954
|
remove_crossings: Optional[Sequence[int]] = None,
|
|
@@ -867,6 +962,7 @@ def simplify_many(
|
|
|
867
962
|
ban_heuristic=ban_heuristic,
|
|
868
963
|
reduction_round=reduction_round,
|
|
869
964
|
max_thread=max_thread,
|
|
965
|
+
timeout=timeout,
|
|
870
966
|
verbose=verbose,
|
|
871
967
|
known_crossingless_components=known_crossingless_components,
|
|
872
968
|
remove_crossings=remove_crossings,
|
|
@@ -884,6 +980,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
884
980
|
parser.add_argument("--ban-heuristic", action="store_true")
|
|
885
981
|
parser.add_argument("--reduction-round", type=int, default=-1)
|
|
886
982
|
parser.add_argument("--max-thread", type=int, default=-1)
|
|
983
|
+
parser.add_argument("--timeout", type=int, default=-1)
|
|
887
984
|
parser.add_argument("--verbose", action="store_true")
|
|
888
985
|
parser.add_argument("--known-crossingless-components", type=int, default=0)
|
|
889
986
|
parser.add_argument("--remove-crossings", help="comma-separated zero-based crossing indices")
|
|
@@ -892,6 +989,8 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
892
989
|
parser.error("--reduction-round must be -1 or a non-negative integer")
|
|
893
990
|
if args.max_thread < -1 or args.max_thread == 0:
|
|
894
991
|
parser.error("--max-thread must be -1 or a positive integer")
|
|
992
|
+
if args.timeout < -1 or args.timeout == 0:
|
|
993
|
+
parser.error("--timeout must be -1 or a positive integer")
|
|
895
994
|
if args.pd_code and args.pd_code_option:
|
|
896
995
|
parser.error("pass either a positional PD code or --pd-code, not both")
|
|
897
996
|
pd_code_text = args.pd_code_option or args.pd_code
|
|
@@ -916,6 +1015,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
916
1015
|
ban_heuristic=args.ban_heuristic,
|
|
917
1016
|
reduction_round=args.reduction_round,
|
|
918
1017
|
max_thread=args.max_thread,
|
|
1018
|
+
timeout=args.timeout,
|
|
919
1019
|
verbose=args.verbose,
|
|
920
1020
|
known_crossingless_components=args.known_crossingless_components,
|
|
921
1021
|
remove_crossings=remove_crossings,
|
|
@@ -923,6 +1023,15 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
923
1023
|
if show_labels:
|
|
924
1024
|
item = {"label": label, **item}
|
|
925
1025
|
batch_payload.append(item)
|
|
1026
|
+
if item.get("timed_out"):
|
|
1027
|
+
exit_code = 2
|
|
1028
|
+
except KeyboardInterrupt:
|
|
1029
|
+
exit_code = 130
|
|
1030
|
+
item = {"error": "interrupted by Ctrl+C"}
|
|
1031
|
+
if show_labels:
|
|
1032
|
+
item = {"label": label, **item}
|
|
1033
|
+
batch_payload.append(item)
|
|
1034
|
+
break
|
|
926
1035
|
except Exception as exc:
|
|
927
1036
|
exit_code = 2
|
|
928
1037
|
item = {"error": str(exc)}
|
|
@@ -931,16 +1040,26 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
931
1040
|
batch_payload.append(item)
|
|
932
1041
|
payload: Any = batch_payload
|
|
933
1042
|
else:
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1043
|
+
try:
|
|
1044
|
+
payload = simplify(
|
|
1045
|
+
pd_code_text or "",
|
|
1046
|
+
max_paths=args.max_paths,
|
|
1047
|
+
ban_heuristic=args.ban_heuristic,
|
|
1048
|
+
reduction_round=args.reduction_round,
|
|
1049
|
+
max_thread=args.max_thread,
|
|
1050
|
+
timeout=args.timeout,
|
|
1051
|
+
verbose=args.verbose,
|
|
1052
|
+
known_crossingless_components=args.known_crossingless_components,
|
|
1053
|
+
remove_crossings=remove_crossings,
|
|
1054
|
+
)
|
|
1055
|
+
if isinstance(payload, dict) and payload.get("timed_out"):
|
|
1056
|
+
exit_code = 2
|
|
1057
|
+
except KeyboardInterrupt:
|
|
1058
|
+
exit_code = 130
|
|
1059
|
+
payload = {"error": "interrupted by Ctrl+C"}
|
|
1060
|
+
except Exception as exc:
|
|
1061
|
+
exit_code = 2
|
|
1062
|
+
payload = {"error": str(exc)}
|
|
944
1063
|
|
|
945
1064
|
print(json.dumps(payload, indent=2))
|
|
946
1065
|
return exit_code
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cpp-pd-code-simplify-interface
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.12
|
|
4
4
|
Summary: Python interface for cpp-pd-code-simplify with runtime C++ compilation.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Author: GGN_2015
|
|
@@ -69,8 +69,14 @@ The default `max_paths=-1` uses deterministic heuristic green-path sampling in
|
|
|
69
69
|
the C++ backend. Use `ban_heuristic=True` to request exhaustive green-path
|
|
70
70
|
enumeration for a manageable input. Use `reduction_round=K` to cap applied
|
|
71
71
|
mid-simplification rounds; the default `-1` runs until stable. Use
|
|
72
|
-
`
|
|
73
|
-
|
|
72
|
+
`timeout=K` to cap a call at `K` seconds; the default `-1` has no timeout. Use
|
|
73
|
+
`verbose=True` to forward timestamped C++ progress logs to stderr. If a call
|
|
74
|
+
times out, the returned dictionary still contains the best PD code found so far
|
|
75
|
+
and sets `timed_out` to `True`. Verbose log lines use local wall-clock time in
|
|
76
|
+
`YYYY-MM-DD HH:MM:SS` format. When `max_thread=-1` reaches a brute-force search
|
|
77
|
+
phase, verbose logs also include `actual_threads`, the worker count selected by
|
|
78
|
+
the C++ backend for that phase. The backend call runs in a helper process, so
|
|
79
|
+
`Ctrl+C` can terminate active C++ work and its worker threads cleanly.
|
|
74
80
|
|
|
75
81
|
Batch use:
|
|
76
82
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
cpp_pd_code_simplify_interface/__init__.py,sha256=aaNwD--zgQX13xiU1hpuvgXy8vVTFGRk-r5zLm8zIRY,447
|
|
2
|
+
cpp_pd_code_simplify_interface/__main__.py,sha256=fdA1QWBe5LNX0fbtaJXa1-dwEhrg_4sS_5UnjaajcMo,80
|
|
3
|
+
cpp_pd_code_simplify_interface/_worker.py,sha256=pgvL3zlAZkUVM033YKAT1geXxcI8TxTUXLp83sgrZgw,1477
|
|
4
|
+
cpp_pd_code_simplify_interface/main.py,sha256=QkhR_2Cq9Ep_8hT5qpFKML7bhq99SuQSKO0jePJHp3U,37007
|
|
5
|
+
cpp_pd_code_simplify_interface/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
6
|
+
cpp_pd_code_simplify_interface-0.1.12.dist-info/entry_points.txt,sha256=ThorC4Enxp317TKITsXm9pE0gUp7pt-pP6Dl5mEPUR8,91
|
|
7
|
+
cpp_pd_code_simplify_interface-0.1.12.dist-info/METADATA,sha256=LECLw_rBE_IhkBnc3fiaJjlqoIwd5TzW9tC4yb0zJe8,4553
|
|
8
|
+
cpp_pd_code_simplify_interface-0.1.12.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
|
|
9
|
+
cpp_pd_code_simplify_interface/data/include/pdcode_simplify/pdcode_simplify.hpp,sha256=ZWZVWuSXN9HgCYd88pfURgLqs-3_0xGDi_ZEPZrYUyY,5135
|
|
10
|
+
cpp_pd_code_simplify_interface/data/src/native_interface.cpp,sha256=-X9ztIyCl5y27Yhj2vCyC4bHCeDpFlcKm6ACPMDoxHs,6708
|
|
11
|
+
cpp_pd_code_simplify_interface/data/src/pdcode_simplify.cpp,sha256=8XTpwAl5kSGsyZpHUIdWZC2NzGrhIMxp9LDcCqFSM8I,95614
|
|
12
|
+
cpp_pd_code_simplify_interface-0.1.12.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
cpp_pd_code_simplify_interface/__init__.py,sha256=aaNwD--zgQX13xiU1hpuvgXy8vVTFGRk-r5zLm8zIRY,447
|
|
2
|
-
cpp_pd_code_simplify_interface/__main__.py,sha256=fdA1QWBe5LNX0fbtaJXa1-dwEhrg_4sS_5UnjaajcMo,80
|
|
3
|
-
cpp_pd_code_simplify_interface/main.py,sha256=4t-6xvjQjsuEWP_oiwedGtgrLYu3316uATrl9t4Q8zs,32778
|
|
4
|
-
cpp_pd_code_simplify_interface/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
5
|
-
cpp_pd_code_simplify_interface-0.1.11.dist-info/entry_points.txt,sha256=ThorC4Enxp317TKITsXm9pE0gUp7pt-pP6Dl5mEPUR8,91
|
|
6
|
-
cpp_pd_code_simplify_interface-0.1.11.dist-info/METADATA,sha256=XtZebJNhEOhA9lHFiGYYHFQJUF5DXS7ItsG0AhOALv8,4073
|
|
7
|
-
cpp_pd_code_simplify_interface-0.1.11.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
|
|
8
|
-
cpp_pd_code_simplify_interface/data/include/pdcode_simplify/pdcode_simplify.hpp,sha256=0WflWW2MB2EAK8GbcKKr9SbnoByMV3hFxt4m4mAerzQ,4917
|
|
9
|
-
cpp_pd_code_simplify_interface/data/src/native_interface.cpp,sha256=16HbKJBPA_EGdbyom4sSoQ7lisDBwaKrl7NsphmlA-k,6555
|
|
10
|
-
cpp_pd_code_simplify_interface/data/src/pdcode_simplify.cpp,sha256=n5rvqpHcUqS87O2AV9duSMAmrh7KUI0HwGHYd5UkMFY,91309
|
|
11
|
-
cpp_pd_code_simplify_interface-0.1.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|