triordinal-dtree 2.0.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.
- triordinal_dtree-2.0.0/PKG-INFO +128 -0
- triordinal_dtree-2.0.0/README.md +104 -0
- triordinal_dtree-2.0.0/pyproject.toml +35 -0
- triordinal_dtree-2.0.0/setup.cfg +4 -0
- triordinal_dtree-2.0.0/tests/test_dtree.py +801 -0
- triordinal_dtree-2.0.0/triordinal/dtree/__init__.py +6 -0
- triordinal_dtree-2.0.0/triordinal/dtree/bench.py +582 -0
- triordinal_dtree-2.0.0/triordinal/dtree/core.py +896 -0
- triordinal_dtree-2.0.0/triordinal_dtree.egg-info/PKG-INFO +128 -0
- triordinal_dtree-2.0.0/triordinal_dtree.egg-info/SOURCES.txt +11 -0
- triordinal_dtree-2.0.0/triordinal_dtree.egg-info/dependency_links.txt +1 -0
- triordinal_dtree-2.0.0/triordinal_dtree.egg-info/requires.txt +1 -0
- triordinal_dtree-2.0.0/triordinal_dtree.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: triordinal-dtree
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: DTree (part of Triordinal): incremental encoding of the topology of directed trees by two projections (Q1, Q2): O(1) reachability, and/or queries on the topology of the tree, dynamic (incremental) updates
|
|
5
|
+
Author-email: Enis Olgac <enis@digraphs.info>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/EnisOlgac/Triordinal
|
|
8
|
+
Project-URL: Documentation, https://github.com/EnisOlgac/Triordinal/blob/main/docs/API.md
|
|
9
|
+
Project-URL: Changelog, https://github.com/EnisOlgac/Triordinal/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Paper, https://doi.org/10.5772/intechopen.1013408
|
|
11
|
+
Project-URL: DTree archive, https://doi.org/10.5281/zenodo.23395710
|
|
12
|
+
Keywords: directed tree,tree topology,reachability,and/or queries,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.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Requires-Dist: triordinal-dlist<3,>=2.0.0
|
|
24
|
+
|
|
25
|
+
# DTree for Python (triordinal-dtree)
|
|
26
|
+
|
|
27
|
+
Python implementation of `DTree`, the incremental encoding of the topology of directed trees by two projections Q1 and Q2 (see the [API reference](https://github.com/EnisOlgac/Triordinal/blob/main/docs/API.md) and the [paper](https://doi.org/10.5772/intechopen.1013408)). No dependencies; Python 3.8+.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
pip install triordinal-dtree
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The package is imported as `triordinal.dtree` (`from triordinal.dtree import DTree`). It continues `dtree-encoding` (imported as `dtree`), whose last versions point here. It depends only on `triordinal-dlist`, the shared list with rational positions.
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from triordinal.dtree import DTree
|
|
37
|
+
|
|
38
|
+
t = DTree("P1")
|
|
39
|
+
t.insert("A", "B")
|
|
40
|
+
t.insert("B", "C")
|
|
41
|
+
|
|
42
|
+
t.can_reach("A", "C") # True
|
|
43
|
+
t.path_to_root("C") # ['C', 'B', 'A']
|
|
44
|
+
t.q1, t.q2 # (['A', 'B', 'C'], ['A', 'B', 'C'])
|
|
45
|
+
|
|
46
|
+
t.insert("A", "D")
|
|
47
|
+
t.cut_n_paste("C", "D") # move subtree C under D
|
|
48
|
+
t.delete("B") # B's children (none left) move up to A
|
|
49
|
+
t.delete_subtree("D") # removes D and C
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Load one of the example files (`parent: child1; child2` per line):
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
t = DTree.from_file("Test.csx") # e.g. examples/Test.csx from the repository
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## API (C# name → Python name)
|
|
59
|
+
|
|
60
|
+
| C# (docs) | Python |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `DTree(id)` | `DTree(tree_id="P1")` |
|
|
63
|
+
| `Insert(parent, child)` | `insert(parent, child)` (last child) |
|
|
64
|
+
| `InsertAfter`, `InsertBefore` | `insert_after(sibling, child)`, `insert_before(sibling, child)` |
|
|
65
|
+
| `AddLine` | `add_line(line)` (`p: c`, `s > c`, `s < c`; also in `from_file`) |
|
|
66
|
+
| `Contains(node)` | `contains(node)` / `node in t` |
|
|
67
|
+
| `GetParent(node)` | `get_parent(node)` (`None` for the root) |
|
|
68
|
+
| `CutNPaste(u, p)` | `cut_n_paste(subtree_root, new_parent)` |
|
|
69
|
+
| `Delete(node)` | `delete(node)`—children move up to the parent |
|
|
70
|
+
| — | `delete_subtree(node)`—removes the node and all descendants |
|
|
71
|
+
| `Q1`, `Q2` | `Q1`, `Q2` (the `DList` projections, for list-level checks); `q1`, `q2` (plain lists, without the `[` `]` markers) |
|
|
72
|
+
| `Source`, `Sink` | `source`, `sink` |
|
|
73
|
+
| `CanReach`, `CanNotReach` | `can_reach`, `can_not_reach` |
|
|
74
|
+
| `IsRoot`, `IsLeaf` | `is_root`, `is_leaf` |
|
|
75
|
+
| `IsAncestor`, `IsDescendant` | `is_ancestor`, `is_descendant` |
|
|
76
|
+
| `SameSubtree`, `SubtreeSize` | `same_subtree`, `subtree_size` (plus `subtree`) |
|
|
77
|
+
| `Depth` | `depth` (root = 0) |
|
|
78
|
+
| `PathToRoot`, `RootToPath` | `path_to_root`, `root_to_path` (plus `path(u, v)`) |
|
|
79
|
+
| `GetNode`, `TryGetNode`, `DNode` | `get_node`, `try_get_node`, `DNode` (node handles; `insert` returns one) |
|
|
80
|
+
| `SubtreeLast` | `subtree_last` (last node of a subtree in Q1) |
|
|
81
|
+
| `NextInQ1` | `next_in_q1` (next node in Q1, the display order; `None` at the end) |
|
|
82
|
+
| `VMin`, `VMax`, `UMin`, `UMax` (of nodes) | `vmin`, `vmax`, `umin`, `umax` |
|
|
83
|
+
| `ReachesAll`, `MayReachSome`, `ReachesSome` | `reaches_all`, `may_reach_some`, `reaches_some` |
|
|
84
|
+
| `ReachedByAll`, `MayBeReachedBySome`, `ReachedBySome` | `reached_by_all`, `may_be_reached_by_some`, `reached_by_some` |
|
|
85
|
+
| `Add`, `Discard`, `Contains` (of a constructed node) | `add`, `discard`, `node in s` |
|
|
86
|
+
| `UMin.Covering` | `covering` (topmost member that reaches a node; `None` if none) |
|
|
87
|
+
|
|
88
|
+
## Semantics
|
|
89
|
+
|
|
90
|
+
- Every method accepts a node name or a node handle (`DNode`). `insert` returns the handle of the new node, `get_node(name)` gives the handle of an existing one. A handle refers directly to the node's positions in Q1 and Q2, so `can_reach` on handles is two position comparisons without any lookup by name. Handles of deleted nodes, or of another tree, are rejected (KeyError) or reported as unreachable.
|
|
91
|
+
|
|
92
|
+
- `can_reach(u, v)` is irreflexive: no node reaches itself, so `can_reach(u, u)` is `False`. (The C# prototype is reflexive.)
|
|
93
|
+
- `is_ancestor(u, v)` equals `can_reach(u, v)` and is likewise proper.
|
|
94
|
+
- `delete(v)` re-attaches v's children to v's parent, in v's place among its siblings.
|
|
95
|
+
- `delete_subtree(v)` removes v with all its descendants and returns them in Q1 order.
|
|
96
|
+
- `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.
|
|
97
|
+
- And/or queries on the topology: 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). Members are added with `add` and removed with `discard`. A constructed node stays valid under insertions and is recomputed automatically after `delete`, `delete_subtree` or `cut_n_paste`. See [and/or queries on the topology](https://github.com/EnisOlgac/Triordinal/blob/main/docs/and-or-queries.md).
|
|
98
|
+
- 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`.
|
|
99
|
+
|
|
100
|
+
## Tests
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
python -m unittest discover -s tests
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Every operation is checked against a brute-force parent/children model on random trees, including random sequences of deletes and moves.
|
|
107
|
+
|
|
108
|
+
## Benchmarks
|
|
109
|
+
|
|
110
|
+
The benchmarks come with the package, so you can measure on your own machine:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
python -m triordinal.dtree.bench # trees of 10,000 and 100,000 nodes
|
|
114
|
+
python -m triordinal.dtree.bench --quick # a few seconds
|
|
115
|
+
python -m triordinal.dtree.bench --dynamic # only the dynamic updates and the tree view
|
|
116
|
+
python -m triordinal.dtree.bench --note "idle machine" # remark for the report
|
|
117
|
+
python -m triordinal.dtree.bench 1000000 # custom sizes
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
In a clone of the repository, `python python/benchmarks/bench.py` runs the same code from the sources.
|
|
121
|
+
|
|
122
|
+
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, and/or queries with constructed nodes, dynamic updates (insertions with 1 or 10 queries each, and static pre/post numbers at depths 100 and 1,000), and a tree view with expand/collapse. Each dynamic measurement is the best of three runs. 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`.
|
|
123
|
+
|
|
124
|
+
Every run also writes its tables as a Markdown report to `benchmarks/python/`—in the current directory, or at the repository root when run inside a clone— named after date and time (for example `2026-10-17_14-18.md`), with a header giving the DTree and Python versions, the operating system and the processor; `--no-save` skips it. The C# benchmarks (`dotnet run --project csharp/Triordinal.Tests -c Release -- bench`) write theirs to `benchmarks/csharp/`.
|
|
125
|
+
|
|
126
|
+
## Provenance
|
|
127
|
+
|
|
128
|
+
Design and API: Enis Olgac. This Python port was written with Claude (Anthropic) from the C# original and the API reference.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# DTree for Python (triordinal-dtree)
|
|
2
|
+
|
|
3
|
+
Python implementation of `DTree`, the incremental encoding of the topology of directed trees by two projections Q1 and Q2 (see the [API reference](https://github.com/EnisOlgac/Triordinal/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 triordinal-dtree
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The package is imported as `triordinal.dtree` (`from triordinal.dtree import DTree`). It continues `dtree-encoding` (imported as `dtree`), whose last versions point here. It depends only on `triordinal-dlist`, the shared list with rational positions.
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from triordinal.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)` (last child) |
|
|
40
|
+
| `InsertAfter`, `InsertBefore` | `insert_after(sibling, child)`, `insert_before(sibling, child)` |
|
|
41
|
+
| `AddLine` | `add_line(line)` (`p: c`, `s > c`, `s < c`; also in `from_file`) |
|
|
42
|
+
| `Contains(node)` | `contains(node)` / `node in t` |
|
|
43
|
+
| `GetParent(node)` | `get_parent(node)` (`None` for the root) |
|
|
44
|
+
| `CutNPaste(u, p)` | `cut_n_paste(subtree_root, new_parent)` |
|
|
45
|
+
| `Delete(node)` | `delete(node)`—children move up to the parent |
|
|
46
|
+
| — | `delete_subtree(node)`—removes the node and all descendants |
|
|
47
|
+
| `Q1`, `Q2` | `Q1`, `Q2` (the `DList` projections, for list-level checks); `q1`, `q2` (plain lists, without the `[` `]` markers) |
|
|
48
|
+
| `Source`, `Sink` | `source`, `sink` |
|
|
49
|
+
| `CanReach`, `CanNotReach` | `can_reach`, `can_not_reach` |
|
|
50
|
+
| `IsRoot`, `IsLeaf` | `is_root`, `is_leaf` |
|
|
51
|
+
| `IsAncestor`, `IsDescendant` | `is_ancestor`, `is_descendant` |
|
|
52
|
+
| `SameSubtree`, `SubtreeSize` | `same_subtree`, `subtree_size` (plus `subtree`) |
|
|
53
|
+
| `Depth` | `depth` (root = 0) |
|
|
54
|
+
| `PathToRoot`, `RootToPath` | `path_to_root`, `root_to_path` (plus `path(u, v)`) |
|
|
55
|
+
| `GetNode`, `TryGetNode`, `DNode` | `get_node`, `try_get_node`, `DNode` (node handles; `insert` returns one) |
|
|
56
|
+
| `SubtreeLast` | `subtree_last` (last node of a subtree in Q1) |
|
|
57
|
+
| `NextInQ1` | `next_in_q1` (next node in Q1, the display order; `None` at the end) |
|
|
58
|
+
| `VMin`, `VMax`, `UMin`, `UMax` (of nodes) | `vmin`, `vmax`, `umin`, `umax` |
|
|
59
|
+
| `ReachesAll`, `MayReachSome`, `ReachesSome` | `reaches_all`, `may_reach_some`, `reaches_some` |
|
|
60
|
+
| `ReachedByAll`, `MayBeReachedBySome`, `ReachedBySome` | `reached_by_all`, `may_be_reached_by_some`, `reached_by_some` |
|
|
61
|
+
| `Add`, `Discard`, `Contains` (of a constructed node) | `add`, `discard`, `node in s` |
|
|
62
|
+
| `UMin.Covering` | `covering` (topmost member that reaches a node; `None` if none) |
|
|
63
|
+
|
|
64
|
+
## Semantics
|
|
65
|
+
|
|
66
|
+
- Every method accepts a node name or a node handle (`DNode`). `insert` returns the handle of the new node, `get_node(name)` gives the handle of an existing one. A handle refers directly to the node's positions in Q1 and Q2, so `can_reach` on handles is two position comparisons without any lookup by name. Handles of deleted nodes, or of another tree, are rejected (KeyError) or reported as unreachable.
|
|
67
|
+
|
|
68
|
+
- `can_reach(u, v)` is irreflexive: no node reaches itself, so `can_reach(u, u)` is `False`. (The C# prototype is reflexive.)
|
|
69
|
+
- `is_ancestor(u, v)` equals `can_reach(u, v)` and is likewise proper.
|
|
70
|
+
- `delete(v)` re-attaches v's children to v's parent, in v's place among its siblings.
|
|
71
|
+
- `delete_subtree(v)` removes v with all its descendants and returns them in Q1 order.
|
|
72
|
+
- `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.
|
|
73
|
+
- And/or queries on the topology: 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). Members are added with `add` and removed with `discard`. A constructed node stays valid under insertions and is recomputed automatically after `delete`, `delete_subtree` or `cut_n_paste`. See [and/or queries on the topology](https://github.com/EnisOlgac/Triordinal/blob/main/docs/and-or-queries.md).
|
|
74
|
+
- 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`.
|
|
75
|
+
|
|
76
|
+
## Tests
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
python -m unittest discover -s tests
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Every operation is checked against a brute-force parent/children model on random trees, including random sequences of deletes and moves.
|
|
83
|
+
|
|
84
|
+
## Benchmarks
|
|
85
|
+
|
|
86
|
+
The benchmarks come with the package, so you can measure on your own machine:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
python -m triordinal.dtree.bench # trees of 10,000 and 100,000 nodes
|
|
90
|
+
python -m triordinal.dtree.bench --quick # a few seconds
|
|
91
|
+
python -m triordinal.dtree.bench --dynamic # only the dynamic updates and the tree view
|
|
92
|
+
python -m triordinal.dtree.bench --note "idle machine" # remark for the report
|
|
93
|
+
python -m triordinal.dtree.bench 1000000 # custom sizes
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
In a clone of the repository, `python python/benchmarks/bench.py` runs the same code from the sources.
|
|
97
|
+
|
|
98
|
+
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, and/or queries with constructed nodes, dynamic updates (insertions with 1 or 10 queries each, and static pre/post numbers at depths 100 and 1,000), and a tree view with expand/collapse. Each dynamic measurement is the best of three runs. 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`.
|
|
99
|
+
|
|
100
|
+
Every run also writes its tables as a Markdown report to `benchmarks/python/`—in the current directory, or at the repository root when run inside a clone— named after date and time (for example `2026-10-17_14-18.md`), with a header giving the DTree and Python versions, the operating system and the processor; `--no-save` skips it. The C# benchmarks (`dotnet run --project csharp/Triordinal.Tests -c Release -- bench`) write theirs to `benchmarks/csharp/`.
|
|
101
|
+
|
|
102
|
+
## Provenance
|
|
103
|
+
|
|
104
|
+
Design and API: Enis Olgac. This Python port was written with Claude (Anthropic) from the C# original and the API reference.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "triordinal-dtree"
|
|
7
|
+
version = "2.0.0"
|
|
8
|
+
description = "DTree (part of Triordinal): incremental encoding of the topology of directed trees by two projections (Q1, Q2): O(1) reachability, and/or queries on the topology of the tree, dynamic (incremental) updates"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
dependencies = ["triordinal-dlist>=2.0.0,<3"]
|
|
13
|
+
authors = [{ name = "Enis Olgac", email = "enis@digraphs.info" }]
|
|
14
|
+
keywords = ["directed tree", "tree topology", "reachability", "and/or queries", "incremental encoding", "dynamic tree", "graph theory", "data structure"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 5 - Production/Stable",
|
|
17
|
+
"Intended Audience :: Science/Research",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
23
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/EnisOlgac/Triordinal"
|
|
28
|
+
Documentation = "https://github.com/EnisOlgac/Triordinal/blob/main/docs/API.md"
|
|
29
|
+
Changelog = "https://github.com/EnisOlgac/Triordinal/blob/main/CHANGELOG.md"
|
|
30
|
+
Paper = "https://doi.org/10.5772/intechopen.1013408"
|
|
31
|
+
"DTree archive" = "https://doi.org/10.5281/zenodo.23395710"
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.packages.find]
|
|
34
|
+
include = ["triordinal.dtree*"]
|
|
35
|
+
namespaces = true
|