dtree-encoding 1.5.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.
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: dtree-encoding
3
+ Version: 1.5.0
4
+ Summary: DTree: incremental encoding of directed trees by two projections (Q1, Q2) with O(1) reachability and set queries
5
+ Author-email: Enis Olgac <enis@digraphs.info>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/EnisOlgac/DTree
8
+ Project-URL: Documentation, https://github.com/EnisOlgac/DTree/blob/main/docs/API.md
9
+ Project-URL: Changelog, https://github.com/EnisOlgac/DTree/blob/main/CHANGELOG.md
10
+ Project-URL: Paper, https://doi.org/10.5772/intechopen.1013408
11
+ Project-URL: Archive, https://doi.org/10.5281/zenodo.23395710
12
+ Keywords: directed tree,reachability,incremental encoding,dynamic tree,graph theory,data structure
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+
24
+ # DTree for Python
25
+
26
+ Python implementation of `DTree`, the incremental encoding of directed trees by two projections Q1 and Q2 (see the [API reference](https://github.com/EnisOlgac/DTree/blob/main/docs/API.md) and the [paper](https://doi.org/10.5772/intechopen.1013408)). No dependencies; Python 3.8+.
27
+
28
+ ```
29
+ pip install dtree-encoding
30
+ ```
31
+
32
+ The package is imported as `dtree`.
33
+
34
+ ```python
35
+ from dtree import DTree
36
+
37
+ t = DTree("P1")
38
+ t.insert("A", "B")
39
+ t.insert("B", "C")
40
+
41
+ t.can_reach("A", "C") # True
42
+ t.path_to_root("C") # ['C', 'B', 'A']
43
+ t.q1, t.q2 # (['A', 'B', 'C'], ['A', 'B', 'C'])
44
+
45
+ t.insert("A", "D")
46
+ t.cut_n_paste("C", "D") # move subtree C under D
47
+ t.delete("B") # B's children (none left) move up to A
48
+ t.delete_subtree("D") # removes D and C
49
+ ```
50
+
51
+ Load one of the example files (`parent: child1; child2` per line):
52
+
53
+ ```python
54
+ t = DTree.from_file("Test.csx") # e.g. examples/Test.csx from the repository
55
+ ```
56
+
57
+ ## API (C# name → Python name)
58
+
59
+ | C# (docs) | Python |
60
+ |---|---|
61
+ | `DTree(id)` | `DTree(tree_id="P1")` |
62
+ | `Insert(parent, child)` | `insert(parent, child)` |
63
+ | `Contains(node)` | `contains(node)` / `node in t` |
64
+ | `GetParent(node)` | `get_parent(node)` (`None` for the root) |
65
+ | `CutNPaste(u, p)` | `cut_n_paste(subtree_root, new_parent)` |
66
+ | `Delete(node)` | `delete(node)`—children move up to the parent |
67
+ | — | `delete_subtree(node)`—removes the node and all descendants |
68
+ | `Q1`, `Q2` | `Q1`, `Q2` (the `DList` projections, for list-level checks); `q1`, `q2` (plain lists, without the `[` `]` markers) |
69
+ | `Source`, `Sink` | `source`, `sink` |
70
+ | `CanReach`, `CanNotReach` | `can_reach`, `can_not_reach` |
71
+ | `IsRoot`, `IsLeaf` | `is_root`, `is_leaf` |
72
+ | `IsAncestor`, `IsDescendant` | `is_ancestor`, `is_descendant` |
73
+ | `SameSubtree`, `SubtreeSize` | `same_subtree`, `subtree_size` (plus `subtree`) |
74
+ | `Depth` | `depth` (root = 0) |
75
+ | `PathToRoot`, `RootToPath` | `path_to_root`, `root_to_path` (plus `path(u, v)`) |
76
+ | `VMin`, `VMax`, `UMin`, `UMax` (of nodes) | `vmin`, `vmax`, `umin`, `umax` |
77
+ | `ReachesAll`, `MayReachSome`, `ReachesSome` | `reaches_all`, `may_reach_some`, `reaches_some` |
78
+ | `ReachedByAll`, `MayBeReachedBySome`, `ReachedBySome` | `reached_by_all`, `may_be_reached_by_some`, `reached_by_some` |
79
+
80
+ ## Semantics
81
+
82
+ - `can_reach(u, v)` is irreflexive: no node reaches itself, so `can_reach(u, u)` is `False`. (The C# prototype is reflexive.)
83
+ - `is_ancestor(u, v)` equals `can_reach(u, v)` and is likewise proper.
84
+ - `delete(v)` re-attaches v's children to v's parent, in v's place among its siblings.
85
+ - `delete_subtree(v)` removes v with all its descendants and returns them in Q1 order.
86
+ - `cut_n_paste(u, p)` moves the subtree rooted at u under p as p's last child; p must not lie inside u's subtree.
87
+ - The constructed nodes `vmin(S)`, `vmax(S)` (S as target) and `umin(S)`, `umax(S)` (S as source) take the minimum or maximum of each index over S, separately in Q1 and Q2. `reaches_all` and `reached_by_all` are exact O(1) tests; `may_reach_some` and `may_be_reached_by_some` are only filters, and `reaches_some` and `reached_by_some` are exact in O(log k). A constructed node stays valid under insertions and is recomputed automatically after `delete`, `delete_subtree` or `cut_n_paste`. See [set queries](https://github.com/EnisOlgac/DTree/blob/main/docs/set-queries.md).
88
+ - Projection positions are fractions: a new node gets the mediant (a+c)/(b+d) of its neighbors, so normally no other node moves. Only rare alternating insertion patterns trigger a local renumbering. Tree depth and width are unbounded. `t.Q1.index(v)` returns a position as a `Fraction`.
89
+
90
+ ## Tests
91
+
92
+ ```
93
+ python -m unittest discover -s tests
94
+ ```
95
+
96
+ Every operation is checked against a brute-force parent/children model on random trees, including random sequences of deletes and moves.
97
+
98
+ ## Benchmarks
99
+
100
+ ```
101
+ python benchmarks/bench.py # trees of 10,000 and 100,000 nodes
102
+ python benchmarks/bench.py --quick # a few seconds
103
+ python benchmarks/bench.py --dynamic # only insertions and queries alternating
104
+ python benchmarks/bench.py 1000000 # custom sizes
105
+ ```
106
+
107
+ The script prints Markdown tables: build time and renumbering counts per tree shape (random, chain, star at the root, star at an inner node, alternating worst case), list growth at either end, and timings for `can_reach`, `depth`, `delete`, `cut_n_paste` and `delete_subtree`, and comparisons with a classical parent walk: reachability by tree depth, set queries with constructed nodes, and dynamic updates (insertions and queries alternating). Each `DList` keeps the counters `renumber_count` and `renumber_moved`, so the same figures are available in your own code via `t.Q1` and `t.Q2`.
108
+
109
+ ## Provenance
110
+
111
+ Design and API: Enis Olgac. This Python port was written with Claude (Anthropic) from the C# original and the API reference.
@@ -0,0 +1,88 @@
1
+ # DTree for Python
2
+
3
+ Python implementation of `DTree`, the incremental encoding of directed trees by two projections Q1 and Q2 (see the [API reference](https://github.com/EnisOlgac/DTree/blob/main/docs/API.md) and the [paper](https://doi.org/10.5772/intechopen.1013408)). No dependencies; Python 3.8+.
4
+
5
+ ```
6
+ pip install dtree-encoding
7
+ ```
8
+
9
+ The package is imported as `dtree`.
10
+
11
+ ```python
12
+ from dtree import DTree
13
+
14
+ t = DTree("P1")
15
+ t.insert("A", "B")
16
+ t.insert("B", "C")
17
+
18
+ t.can_reach("A", "C") # True
19
+ t.path_to_root("C") # ['C', 'B', 'A']
20
+ t.q1, t.q2 # (['A', 'B', 'C'], ['A', 'B', 'C'])
21
+
22
+ t.insert("A", "D")
23
+ t.cut_n_paste("C", "D") # move subtree C under D
24
+ t.delete("B") # B's children (none left) move up to A
25
+ t.delete_subtree("D") # removes D and C
26
+ ```
27
+
28
+ Load one of the example files (`parent: child1; child2` per line):
29
+
30
+ ```python
31
+ t = DTree.from_file("Test.csx") # e.g. examples/Test.csx from the repository
32
+ ```
33
+
34
+ ## API (C# name → Python name)
35
+
36
+ | C# (docs) | Python |
37
+ |---|---|
38
+ | `DTree(id)` | `DTree(tree_id="P1")` |
39
+ | `Insert(parent, child)` | `insert(parent, child)` |
40
+ | `Contains(node)` | `contains(node)` / `node in t` |
41
+ | `GetParent(node)` | `get_parent(node)` (`None` for the root) |
42
+ | `CutNPaste(u, p)` | `cut_n_paste(subtree_root, new_parent)` |
43
+ | `Delete(node)` | `delete(node)`—children move up to the parent |
44
+ | — | `delete_subtree(node)`—removes the node and all descendants |
45
+ | `Q1`, `Q2` | `Q1`, `Q2` (the `DList` projections, for list-level checks); `q1`, `q2` (plain lists, without the `[` `]` markers) |
46
+ | `Source`, `Sink` | `source`, `sink` |
47
+ | `CanReach`, `CanNotReach` | `can_reach`, `can_not_reach` |
48
+ | `IsRoot`, `IsLeaf` | `is_root`, `is_leaf` |
49
+ | `IsAncestor`, `IsDescendant` | `is_ancestor`, `is_descendant` |
50
+ | `SameSubtree`, `SubtreeSize` | `same_subtree`, `subtree_size` (plus `subtree`) |
51
+ | `Depth` | `depth` (root = 0) |
52
+ | `PathToRoot`, `RootToPath` | `path_to_root`, `root_to_path` (plus `path(u, v)`) |
53
+ | `VMin`, `VMax`, `UMin`, `UMax` (of nodes) | `vmin`, `vmax`, `umin`, `umax` |
54
+ | `ReachesAll`, `MayReachSome`, `ReachesSome` | `reaches_all`, `may_reach_some`, `reaches_some` |
55
+ | `ReachedByAll`, `MayBeReachedBySome`, `ReachedBySome` | `reached_by_all`, `may_be_reached_by_some`, `reached_by_some` |
56
+
57
+ ## Semantics
58
+
59
+ - `can_reach(u, v)` is irreflexive: no node reaches itself, so `can_reach(u, u)` is `False`. (The C# prototype is reflexive.)
60
+ - `is_ancestor(u, v)` equals `can_reach(u, v)` and is likewise proper.
61
+ - `delete(v)` re-attaches v's children to v's parent, in v's place among its siblings.
62
+ - `delete_subtree(v)` removes v with all its descendants and returns them in Q1 order.
63
+ - `cut_n_paste(u, p)` moves the subtree rooted at u under p as p's last child; p must not lie inside u's subtree.
64
+ - The constructed nodes `vmin(S)`, `vmax(S)` (S as target) and `umin(S)`, `umax(S)` (S as source) take the minimum or maximum of each index over S, separately in Q1 and Q2. `reaches_all` and `reached_by_all` are exact O(1) tests; `may_reach_some` and `may_be_reached_by_some` are only filters, and `reaches_some` and `reached_by_some` are exact in O(log k). A constructed node stays valid under insertions and is recomputed automatically after `delete`, `delete_subtree` or `cut_n_paste`. See [set queries](https://github.com/EnisOlgac/DTree/blob/main/docs/set-queries.md).
65
+ - Projection positions are fractions: a new node gets the mediant (a+c)/(b+d) of its neighbors, so normally no other node moves. Only rare alternating insertion patterns trigger a local renumbering. Tree depth and width are unbounded. `t.Q1.index(v)` returns a position as a `Fraction`.
66
+
67
+ ## Tests
68
+
69
+ ```
70
+ python -m unittest discover -s tests
71
+ ```
72
+
73
+ Every operation is checked against a brute-force parent/children model on random trees, including random sequences of deletes and moves.
74
+
75
+ ## Benchmarks
76
+
77
+ ```
78
+ python benchmarks/bench.py # trees of 10,000 and 100,000 nodes
79
+ python benchmarks/bench.py --quick # a few seconds
80
+ python benchmarks/bench.py --dynamic # only insertions and queries alternating
81
+ python benchmarks/bench.py 1000000 # custom sizes
82
+ ```
83
+
84
+ The script prints Markdown tables: build time and renumbering counts per tree shape (random, chain, star at the root, star at an inner node, alternating worst case), list growth at either end, and timings for `can_reach`, `depth`, `delete`, `cut_n_paste` and `delete_subtree`, and comparisons with a classical parent walk: reachability by tree depth, set queries with constructed nodes, and dynamic updates (insertions and queries alternating). Each `DList` keeps the counters `renumber_count` and `renumber_moved`, so the same figures are available in your own code via `t.Q1` and `t.Q2`.
85
+
86
+ ## Provenance
87
+
88
+ Design and API: Enis Olgac. This Python port was written with Claude (Anthropic) from the C# original and the API reference.
@@ -0,0 +1,6 @@
1
+ """DTree: directed tree library with dual projections Q1 and Q2."""
2
+
3
+ from .dtree import SINK, SOURCE, DList, DTree, UMax, UMin, VMax, VMin
4
+
5
+ __all__ = ["DTree", "DList", "VMin", "VMax", "UMin", "UMax", "SOURCE", "SINK"]
6
+ __version__ = "1.5.0"