cpp-pd-code-simplify-interface 0.1.9__tar.gz → 0.1.11__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cpp-pd-code-simplify-interface
3
- Version: 0.1.9
3
+ Version: 0.1.11
4
4
  Summary: Python interface for cpp-pd-code-simplify with runtime C++ compilation.
5
5
  License-Expression: MIT
6
6
  Author: GGN_2015
@@ -59,9 +59,11 @@ result = simplify.simplify(pd_code)
59
59
  print(result["final_pd_code"])
60
60
  ```
61
61
 
62
- Returned `final_pd_code` strings are normalized so the smallest edge label is
63
- `1`. This is applied only at the final JSON boundary; the C++ backend keeps its
64
- internal numbering unchanged while simplifying.
62
+ Returned `final_pd_code` strings are normalized for display: each crossing is
63
+ written from the under-incoming edge, labels are renumbered along oriented
64
+ components from `1`, and crossing rows are sorted lexicographically. This is
65
+ applied only at the final JSON boundary; the C++ backend keeps its internal
66
+ numbering unchanged while simplifying.
65
67
 
66
68
  The default `max_paths=-1` uses deterministic heuristic green-path sampling in
67
69
  the C++ backend. Use `ban_heuristic=True` to request exhaustive green-path
@@ -39,9 +39,11 @@ result = simplify.simplify(pd_code)
39
39
  print(result["final_pd_code"])
40
40
  ```
41
41
 
42
- Returned `final_pd_code` strings are normalized so the smallest edge label is
43
- `1`. This is applied only at the final JSON boundary; the C++ backend keeps its
44
- internal numbering unchanged while simplifying.
42
+ Returned `final_pd_code` strings are normalized for display: each crossing is
43
+ written from the under-incoming edge, labels are renumbered along oriented
44
+ components from `1`, and crossing rows are sorted lexicographically. This is
45
+ applied only at the final JSON boundary; the C++ backend keeps its internal
46
+ numbering unchanged while simplifying.
45
47
 
46
48
  The default `max_paths=-1` uses deterministic heuristic green-path sampling in
47
49
  the C++ backend. Use `ban_heuristic=True` to request exhaustive green-path
@@ -510,8 +510,10 @@ std::vector<std::vector<int>> raw_faces_from_pd_code(const PDCode& code) {
510
510
  struct Diagram {
511
511
  PDCode code;
512
512
  std::vector<CrossingState> crossings;
513
+ std::vector<int> rotations;
513
514
 
514
- explicit Diagram(PDCode input) : code(std::move(input)), crossings(code.size()) {
515
+ explicit Diagram(PDCode input)
516
+ : code(std::move(input)), crossings(code.size()), rotations(code.size(), 0) {
515
517
  build_adjacency();
516
518
  auto starts = component_starts_from_pd();
517
519
  orient_crossings(starts);
@@ -533,6 +535,10 @@ struct Diagram {
533
535
  return Endpoint{endpoint.crossing, positive_mod(endpoint.strand + offset, 4)};
534
536
  }
535
537
 
538
+ int label_at(int crossing, int strand) const {
539
+ return code.at(crossing).at(positive_mod(strand + rotations.at(crossing), 4));
540
+ }
541
+
536
542
  std::vector<Endpoint> crossing_entries() const {
537
543
  std::vector<Endpoint> entries;
538
544
  entries.reserve(crossings.size() * 2);
@@ -715,6 +721,7 @@ private:
715
721
 
716
722
  void rotate_crossing_180(int crossing) {
717
723
  auto old_adjacent = crossings[crossing].adjacent;
724
+ rotations[crossing] = positive_mod(rotations[crossing] + 2, 4);
718
725
  bool old_directions[4][4]{};
719
726
  for (int a = 0; a < 4; ++a) {
720
727
  for (int b = 0; b < 4; ++b) {
@@ -1873,28 +1880,64 @@ std::string format_final_pd_code(const PDCode& code) {
1873
1880
  return format_pd_code(code);
1874
1881
  }
1875
1882
 
1876
- bool has_label = false;
1877
- int minimum_label = 0;
1878
- for (const Crossing& crossing : code) {
1879
- for (int label : crossing) {
1880
- if (!has_label || label < minimum_label) {
1881
- minimum_label = label;
1882
- has_label = true;
1883
+ const Diagram diagram(code);
1884
+ PDCode oriented(code.size());
1885
+ std::set<int> labels;
1886
+ std::map<int, int> next_label;
1887
+
1888
+ for (int crossing = 0; crossing < static_cast<int>(code.size()); ++crossing) {
1889
+ for (int strand = 0; strand < 4; ++strand) {
1890
+ const int label = diagram.label_at(crossing, strand);
1891
+ oriented[crossing][strand] = label;
1892
+ labels.insert(label);
1893
+ }
1894
+
1895
+ if (!diagram.crossings[crossing].directions[0][2]) {
1896
+ throw std::invalid_argument("Could not orient final PD crossing from an under-incoming strand");
1897
+ }
1898
+ for (int tail = 0; tail < 4; ++tail) {
1899
+ for (int head = 0; head < 4; ++head) {
1900
+ if (!diagram.crossings[crossing].directions[tail][head]) {
1901
+ continue;
1902
+ }
1903
+ const int in_label = diagram.label_at(crossing, tail);
1904
+ const int out_label = diagram.label_at(crossing, head);
1905
+ const auto inserted = next_label.insert(std::make_pair(in_label, out_label));
1906
+ if (!inserted.second && inserted.first->second != out_label) {
1907
+ throw std::invalid_argument("Final PD component orientation is inconsistent");
1908
+ }
1883
1909
  }
1884
1910
  }
1885
1911
  }
1886
- if (!has_label || minimum_label == 1) {
1887
- return format_pd_code(code);
1912
+
1913
+ std::map<int, int> relabel;
1914
+ int next_output_label = 1;
1915
+ for (int start : labels) {
1916
+ if (relabel.count(start) != 0) {
1917
+ continue;
1918
+ }
1919
+
1920
+ int current = start;
1921
+ while (relabel.count(current) == 0) {
1922
+ relabel[current] = next_output_label++;
1923
+ const auto next = next_label.find(current);
1924
+ if (next == next_label.end()) {
1925
+ throw std::invalid_argument("Final PD component orientation is incomplete");
1926
+ }
1927
+ current = next->second;
1928
+ }
1929
+ if (current != start) {
1930
+ throw std::invalid_argument("Final PD component orientation reached another component");
1931
+ }
1888
1932
  }
1889
1933
 
1890
- PDCode shifted = code;
1891
- const int offset = 1 - minimum_label;
1892
- for (Crossing& crossing : shifted) {
1934
+ for (Crossing& crossing : oriented) {
1893
1935
  for (int& label : crossing) {
1894
- label += offset;
1936
+ label = relabel.at(label);
1895
1937
  }
1896
1938
  }
1897
- return format_pd_code(shifted);
1939
+ std::sort(oriented.begin(), oriented.end());
1940
+ return format_pd_code(oriented);
1898
1941
  }
1899
1942
 
1900
1943
  std::string format_endpoint(const Endpoint& endpoint) {
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cpp-pd-code-simplify-interface"
3
- version = "0.1.9"
3
+ version = "0.1.11"
4
4
  description = "Python interface for cpp-pd-code-simplify with runtime C++ compilation."
5
5
  authors = [
6
6
  {name = "GGN_2015", email = "neko@jlulug.org"}