spatial-graph 0.0.1__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.
- spatial_graph-0.0.1/.cruft.json +20 -0
- spatial_graph-0.0.1/.github/workflows/ci.yaml +80 -0
- spatial_graph-0.0.1/.gitignore +13 -0
- spatial_graph-0.0.1/.pre-commit-config.yaml +27 -0
- spatial_graph-0.0.1/LICENSE +21 -0
- spatial_graph-0.0.1/PKG-INFO +130 -0
- spatial_graph-0.0.1/README.md +112 -0
- spatial_graph-0.0.1/pyproject.toml +32 -0
- spatial_graph-0.0.1/spatial_graph/__init__.py +15 -0
- spatial_graph-0.0.1/spatial_graph/dtypes.py +130 -0
- spatial_graph-0.0.1/spatial_graph/graph/__init__.py +3 -0
- spatial_graph-0.0.1/spatial_graph/graph/graph.py +226 -0
- spatial_graph-0.0.1/spatial_graph/graph/src/LICENSE.txt +7 -0
- spatial_graph-0.0.1/spatial_graph/graph/src/graph_lite.h +1357 -0
- spatial_graph-0.0.1/spatial_graph/graph/wrapper_template.pyx +654 -0
- spatial_graph-0.0.1/spatial_graph/rtree/__init__.py +5 -0
- spatial_graph-0.0.1/spatial_graph/rtree/line_rtree.py +156 -0
- spatial_graph-0.0.1/spatial_graph/rtree/point_rtree.py +6 -0
- spatial_graph-0.0.1/spatial_graph/rtree/rtree.py +125 -0
- spatial_graph-0.0.1/spatial_graph/rtree/src/ARCHITECTURE.md +162 -0
- spatial_graph-0.0.1/spatial_graph/rtree/src/LICENSE +20 -0
- spatial_graph-0.0.1/spatial_graph/rtree/src/config.h +13 -0
- spatial_graph-0.0.1/spatial_graph/rtree/src/rtree.c +1021 -0
- spatial_graph-0.0.1/spatial_graph/rtree/src/rtree.h +97 -0
- spatial_graph-0.0.1/spatial_graph/rtree/wrapper_template.pyx +356 -0
- spatial_graph-0.0.1/spatial_graph/spatial_graph.py +95 -0
- spatial_graph-0.0.1/tests/test_assert.py +2 -0
- spatial_graph-0.0.1/tests/test_attributes.py +97 -0
- spatial_graph-0.0.1/tests/test_graph.py +244 -0
- spatial_graph-0.0.1/tests/test_rtree.py +262 -0
- spatial_graph-0.0.1/tests/test_spatial_graph.py +98 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"template": "https://github.com/adjavon/pycookie/",
|
|
3
|
+
"commit": "d7bd6b8521627b130001b270383b72bfed608ab3",
|
|
4
|
+
"checkout": null,
|
|
5
|
+
"context": {
|
|
6
|
+
"cookiecutter": {
|
|
7
|
+
"full_name": "Jan Funke",
|
|
8
|
+
"email": "funkej@janelia.hhmi.org",
|
|
9
|
+
"github_username": "funkelab",
|
|
10
|
+
"project_name": "spatial_graph",
|
|
11
|
+
"project_slug": "spatial_graph",
|
|
12
|
+
"project_short_description": "A spatial graph datastructure for python.",
|
|
13
|
+
"_copy_without_render": [
|
|
14
|
+
".github/workflows/*"
|
|
15
|
+
],
|
|
16
|
+
"_template": "https://github.com/adjavon/pycookie/"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"directory": null
|
|
20
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
tags: [v*]
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
lint:
|
|
19
|
+
name: Lint
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
- name: Run pre-commit
|
|
24
|
+
run: pipx run pre-commit run --all-files
|
|
25
|
+
|
|
26
|
+
test:
|
|
27
|
+
runs-on: ${{ matrix.os }}
|
|
28
|
+
strategy:
|
|
29
|
+
fail-fast: false
|
|
30
|
+
matrix:
|
|
31
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
32
|
+
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
|
33
|
+
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v2
|
|
36
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
37
|
+
uses: actions/setup-python@v4
|
|
38
|
+
with:
|
|
39
|
+
python-version: ${{ matrix.python-version }}
|
|
40
|
+
- name: Install dependencies
|
|
41
|
+
run: |
|
|
42
|
+
pip install ".[dev]"
|
|
43
|
+
- name: Test with pytest
|
|
44
|
+
run: |
|
|
45
|
+
pytest --color=yes -v tests
|
|
46
|
+
|
|
47
|
+
deploy:
|
|
48
|
+
name: Deploy
|
|
49
|
+
needs: test
|
|
50
|
+
if: success() && startsWith(github.ref, 'refs/tags/') && github.event_name != 'schedule'
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
|
|
53
|
+
permissions:
|
|
54
|
+
id-token: write
|
|
55
|
+
contents: write
|
|
56
|
+
|
|
57
|
+
steps:
|
|
58
|
+
- uses: actions/checkout@v4
|
|
59
|
+
with:
|
|
60
|
+
fetch-depth: 0
|
|
61
|
+
|
|
62
|
+
- name: 🐍 Set up Python
|
|
63
|
+
uses: actions/setup-python@v5
|
|
64
|
+
with:
|
|
65
|
+
python-version: "3.x"
|
|
66
|
+
|
|
67
|
+
- name: 👷 Build
|
|
68
|
+
run: |
|
|
69
|
+
python -m pip install build
|
|
70
|
+
python -m build
|
|
71
|
+
|
|
72
|
+
- name: 🚢 Publish to PyPI
|
|
73
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
74
|
+
with:
|
|
75
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
76
|
+
|
|
77
|
+
- uses: softprops/action-gh-release@v2
|
|
78
|
+
with:
|
|
79
|
+
generate_release_notes: true
|
|
80
|
+
files: "./dist/*"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
ci:
|
|
2
|
+
autoupdate_schedule: monthly
|
|
3
|
+
autofix_commit_msg: "style(pre-commit.ci): auto fixes [...]"
|
|
4
|
+
autoupdate_commit_msg: "ci(pre-commit.ci): autoupdate"
|
|
5
|
+
|
|
6
|
+
default_install_hook_types: [pre-commit, commit-msg]
|
|
7
|
+
|
|
8
|
+
repos:
|
|
9
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
10
|
+
rev: v5.0.0
|
|
11
|
+
hooks:
|
|
12
|
+
- id: trailing-whitespace
|
|
13
|
+
- id: end-of-file-fixer
|
|
14
|
+
- id: check-yaml
|
|
15
|
+
- id: check-added-large-files
|
|
16
|
+
|
|
17
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
18
|
+
rev: v0.7.2
|
|
19
|
+
hooks:
|
|
20
|
+
- id: ruff
|
|
21
|
+
args: [--fix, --unsafe-fixes]
|
|
22
|
+
- id: ruff-format
|
|
23
|
+
|
|
24
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
25
|
+
rev: v1.13.0
|
|
26
|
+
hooks:
|
|
27
|
+
- id: mypy
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Funke lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spatial-graph
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A spatial graph datastructure for python.
|
|
5
|
+
Project-URL: homepage, https://github.com/funkelab/spatial_graph
|
|
6
|
+
Project-URL: repository, https://github.com/funkelab/spatial_graph
|
|
7
|
+
Author-email: Jan Funke <funkej@janelia.hhmi.org>
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Requires-Dist: cheetah3
|
|
12
|
+
Requires-Dist: numpy
|
|
13
|
+
Requires-Dist: setuptools>=75.8.0
|
|
14
|
+
Requires-Dist: witty>=v0.2.0
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: pytest>=8.3.4; extra == 'dev'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# spatial_graph
|
|
20
|
+
|
|
21
|
+
[](https://github.com/funkelab/spatial_graph/actions/workflows/ci.yaml)
|
|
22
|
+
|
|
23
|
+
`spatial_graph` provides a data structure for directed and undirected graphs,
|
|
24
|
+
where each node has an nD position (in time or space).
|
|
25
|
+
|
|
26
|
+
Design Principles
|
|
27
|
+
=================
|
|
28
|
+
|
|
29
|
+
Goals
|
|
30
|
+
-----
|
|
31
|
+
|
|
32
|
+
* support for arbitrary number of dimensions
|
|
33
|
+
* typed node identifiers and attributes
|
|
34
|
+
* any fixed-length type that is supported by `numpy`
|
|
35
|
+
* efficient node/edge queries by
|
|
36
|
+
* ROI
|
|
37
|
+
* kNN (by points / lines)
|
|
38
|
+
* numpy-like interface for efficient:
|
|
39
|
+
* graph population and manipulation
|
|
40
|
+
* query results
|
|
41
|
+
* attribute access
|
|
42
|
+
* minimal memory footprint
|
|
43
|
+
* minimal dependencies
|
|
44
|
+
* `cython` / `witty` / `cheetah3` for runtime compilation
|
|
45
|
+
* numpy for array interfaces
|
|
46
|
+
* PYX API for graph algorithms in C/C++
|
|
47
|
+
|
|
48
|
+
Non-Goals
|
|
49
|
+
---------
|
|
50
|
+
|
|
51
|
+
* graph algorithms
|
|
52
|
+
* I/O
|
|
53
|
+
* non-typed arguments
|
|
54
|
+
* non-spatial graphs
|
|
55
|
+
* out-of-memory support
|
|
56
|
+
* networkx compatibility
|
|
57
|
+
|
|
58
|
+
Python API
|
|
59
|
+
==========
|
|
60
|
+
|
|
61
|
+
Graph creation:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
graph = sg.SpatialGraph(
|
|
65
|
+
ndims=3,
|
|
66
|
+
node_dtype="uint64",
|
|
67
|
+
node_attr_dtypes={"position": "double[3]"},
|
|
68
|
+
edge_attr_dtypes={"score": "float32"},
|
|
69
|
+
position_attr="position",
|
|
70
|
+
directed=False,
|
|
71
|
+
)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Adding nodes/edges:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
graph.add_nodes(
|
|
78
|
+
np.array([1, 2, 3, 4, 5], dtype="uint64"),
|
|
79
|
+
position=np.array(
|
|
80
|
+
[
|
|
81
|
+
[0.1, 0.1, 0.1],
|
|
82
|
+
[0.2, 0.2, 0.2],
|
|
83
|
+
[0.3, 0.3, 0.3],
|
|
84
|
+
[0.4, 0.4, 0.4],
|
|
85
|
+
[0.5, 0.5, 0.5],
|
|
86
|
+
],
|
|
87
|
+
dtype="double",
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
graph.add_edges(
|
|
92
|
+
np.array([[1, 2], [3, 4], [5, 1]], dtype="uint64"),
|
|
93
|
+
score=np.array([0.2, 0.3, 0.4], dtype="float32"),
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Query nodes/edges in ROI:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
# nodes/edges will be numpy arrays of dtype uint64 and shape (n,)/(n, 2)
|
|
101
|
+
nodes = graph.query_nodes_in_roi(np.array([[0.0, 0.0, 0.0], [0.25, 0.25, 0.25]]))
|
|
102
|
+
edges = graph.query_edges_in_roi(np.array([[0.0, 0.0, 0.0], [0.25, 0.25, 0.25]]))
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Query nodes/edges by position:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
nodes = graph.query_nearest_nodes(np.array([0.3, 0.3, 0.3]), k=3)
|
|
109
|
+
edges = graph.query_nearest_edges(np.array([0.3, 0.3, 0.3]), k=3)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Access node/edge attributes:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
node_positions = graph.node_attrs[nodes].position
|
|
116
|
+
edge_scores = graph.edge_attrs[edges].score
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Delete nodes/edges:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
graph.remove_nodes(nodes[:1000])
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Implementation Details
|
|
126
|
+
======================
|
|
127
|
+
|
|
128
|
+
A `SpatialGraph` consists of three data structures:
|
|
129
|
+
* The `Graph` itself, holding nodes, edges, and their attributes ([graphlite](https://github.com/haasdo95/graphlite)).
|
|
130
|
+
* Two R-trees for spatial node and edge queries (based on [rtree.c](https://github.com/tidwall/rtree.c)).
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# spatial_graph
|
|
2
|
+
|
|
3
|
+
[](https://github.com/funkelab/spatial_graph/actions/workflows/ci.yaml)
|
|
4
|
+
|
|
5
|
+
`spatial_graph` provides a data structure for directed and undirected graphs,
|
|
6
|
+
where each node has an nD position (in time or space).
|
|
7
|
+
|
|
8
|
+
Design Principles
|
|
9
|
+
=================
|
|
10
|
+
|
|
11
|
+
Goals
|
|
12
|
+
-----
|
|
13
|
+
|
|
14
|
+
* support for arbitrary number of dimensions
|
|
15
|
+
* typed node identifiers and attributes
|
|
16
|
+
* any fixed-length type that is supported by `numpy`
|
|
17
|
+
* efficient node/edge queries by
|
|
18
|
+
* ROI
|
|
19
|
+
* kNN (by points / lines)
|
|
20
|
+
* numpy-like interface for efficient:
|
|
21
|
+
* graph population and manipulation
|
|
22
|
+
* query results
|
|
23
|
+
* attribute access
|
|
24
|
+
* minimal memory footprint
|
|
25
|
+
* minimal dependencies
|
|
26
|
+
* `cython` / `witty` / `cheetah3` for runtime compilation
|
|
27
|
+
* numpy for array interfaces
|
|
28
|
+
* PYX API for graph algorithms in C/C++
|
|
29
|
+
|
|
30
|
+
Non-Goals
|
|
31
|
+
---------
|
|
32
|
+
|
|
33
|
+
* graph algorithms
|
|
34
|
+
* I/O
|
|
35
|
+
* non-typed arguments
|
|
36
|
+
* non-spatial graphs
|
|
37
|
+
* out-of-memory support
|
|
38
|
+
* networkx compatibility
|
|
39
|
+
|
|
40
|
+
Python API
|
|
41
|
+
==========
|
|
42
|
+
|
|
43
|
+
Graph creation:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
graph = sg.SpatialGraph(
|
|
47
|
+
ndims=3,
|
|
48
|
+
node_dtype="uint64",
|
|
49
|
+
node_attr_dtypes={"position": "double[3]"},
|
|
50
|
+
edge_attr_dtypes={"score": "float32"},
|
|
51
|
+
position_attr="position",
|
|
52
|
+
directed=False,
|
|
53
|
+
)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Adding nodes/edges:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
graph.add_nodes(
|
|
60
|
+
np.array([1, 2, 3, 4, 5], dtype="uint64"),
|
|
61
|
+
position=np.array(
|
|
62
|
+
[
|
|
63
|
+
[0.1, 0.1, 0.1],
|
|
64
|
+
[0.2, 0.2, 0.2],
|
|
65
|
+
[0.3, 0.3, 0.3],
|
|
66
|
+
[0.4, 0.4, 0.4],
|
|
67
|
+
[0.5, 0.5, 0.5],
|
|
68
|
+
],
|
|
69
|
+
dtype="double",
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
graph.add_edges(
|
|
74
|
+
np.array([[1, 2], [3, 4], [5, 1]], dtype="uint64"),
|
|
75
|
+
score=np.array([0.2, 0.3, 0.4], dtype="float32"),
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Query nodes/edges in ROI:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
# nodes/edges will be numpy arrays of dtype uint64 and shape (n,)/(n, 2)
|
|
83
|
+
nodes = graph.query_nodes_in_roi(np.array([[0.0, 0.0, 0.0], [0.25, 0.25, 0.25]]))
|
|
84
|
+
edges = graph.query_edges_in_roi(np.array([[0.0, 0.0, 0.0], [0.25, 0.25, 0.25]]))
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Query nodes/edges by position:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
nodes = graph.query_nearest_nodes(np.array([0.3, 0.3, 0.3]), k=3)
|
|
91
|
+
edges = graph.query_nearest_edges(np.array([0.3, 0.3, 0.3]), k=3)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Access node/edge attributes:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
node_positions = graph.node_attrs[nodes].position
|
|
98
|
+
edge_scores = graph.edge_attrs[edges].score
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Delete nodes/edges:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
graph.remove_nodes(nodes[:1000])
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Implementation Details
|
|
108
|
+
======================
|
|
109
|
+
|
|
110
|
+
A `SpatialGraph` consists of three data structures:
|
|
111
|
+
* The `Graph` itself, holding nodes, edges, and their attributes ([graphlite](https://github.com/haasdo95/graphlite)).
|
|
112
|
+
* Two R-trees for spatial node and edge queries (based on [rtree.c](https://github.com/tidwall/rtree.c)).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "spatial-graph"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "A spatial graph datastructure for python."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.9"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [
|
|
9
|
+
{ email = "funkej@janelia.hhmi.org", name = "Jan Funke" },
|
|
10
|
+
]
|
|
11
|
+
dependencies = [
|
|
12
|
+
"witty>=v0.2.0",
|
|
13
|
+
"cheetah3",
|
|
14
|
+
"numpy",
|
|
15
|
+
"setuptools>=75.8.0",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.urls]
|
|
19
|
+
homepage = "https://github.com/funkelab/spatial_graph"
|
|
20
|
+
repository = "https://github.com/funkelab/spatial_graph"
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
dev = [
|
|
24
|
+
"pytest>=8.3.4",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[tool.hatch.metadata]
|
|
28
|
+
allow-direct-references = true
|
|
29
|
+
|
|
30
|
+
[build-system]
|
|
31
|
+
requires = ["hatchling"]
|
|
32
|
+
build-backend = "hatchling.build"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
__version__ = version("spatial_graph")
|
|
5
|
+
except PackageNotFoundError:
|
|
6
|
+
__version__ = "unknown"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
from .rtree import PointRTree
|
|
10
|
+
from .rtree import LineRTree
|
|
11
|
+
from .graph import Graph
|
|
12
|
+
from .spatial_graph import SpatialGraph
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = ["PointRTree", "LineRTree", "Graph", "SpatialGraph"]
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DType:
|
|
5
|
+
def __init__(self, dtype_str):
|
|
6
|
+
self.as_string = dtype_str
|
|
7
|
+
self.is_array = self.__is_array(dtype_str)
|
|
8
|
+
|
|
9
|
+
if self.is_array:
|
|
10
|
+
self.base, self.size = self.__parse_array_dtype(dtype_str)
|
|
11
|
+
self.shape = (self.size,)
|
|
12
|
+
else:
|
|
13
|
+
self.base = dtype_str
|
|
14
|
+
self.size = None
|
|
15
|
+
self.shape = ()
|
|
16
|
+
|
|
17
|
+
def __is_array(self, dtype):
|
|
18
|
+
if "[" in dtype:
|
|
19
|
+
if "]" not in dtype:
|
|
20
|
+
raise RuntimeError(f"invalid array(?) dtype {dtype}")
|
|
21
|
+
return True
|
|
22
|
+
return False
|
|
23
|
+
|
|
24
|
+
def __parse_array_dtype(self, dtype):
|
|
25
|
+
dtype, size = dtype.split("[")
|
|
26
|
+
size = int(size.split("]")[0])
|
|
27
|
+
|
|
28
|
+
return dtype, size
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def base_c_type(self):
|
|
32
|
+
"""Convert the base of this DType into the equivalent C/C++ type."""
|
|
33
|
+
|
|
34
|
+
if self.base == "float32" or self.base == "float":
|
|
35
|
+
return "float"
|
|
36
|
+
elif self.base == "float64" or self.base == "double":
|
|
37
|
+
return "double"
|
|
38
|
+
else:
|
|
39
|
+
# this might not work for all of them, this is just a fallback
|
|
40
|
+
return np.dtype(self.base).name + "_t"
|
|
41
|
+
|
|
42
|
+
def to_c_decl(self, name):
|
|
43
|
+
"""Convert this dtype to the equivalent C/C++ declaration with the
|
|
44
|
+
given name:
|
|
45
|
+
|
|
46
|
+
"base_c_type name" if not an array
|
|
47
|
+
"base_c_type name[size]" if an array type
|
|
48
|
+
"""
|
|
49
|
+
# is this an array type?
|
|
50
|
+
if self.is_array:
|
|
51
|
+
suffix = f"[{self.size}]"
|
|
52
|
+
else:
|
|
53
|
+
suffix = ""
|
|
54
|
+
|
|
55
|
+
return self.base_c_type + " " + name + suffix
|
|
56
|
+
|
|
57
|
+
def to_pyxtype(self, use_memory_view=False, add_dim=False):
|
|
58
|
+
"""Convert this dtype to the equivalent PYX type.
|
|
59
|
+
|
|
60
|
+
"base_c_type"
|
|
61
|
+
"base_c_type[size]" if an array type
|
|
62
|
+
"base_c_type[::1]" if an array type and use_memory_view
|
|
63
|
+
"base_c_type[::1]" if not an array type and add_dim
|
|
64
|
+
"base_c_type[:, ::1]" if an array type and add_dim
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
|
|
68
|
+
use_memory_view:
|
|
69
|
+
|
|
70
|
+
If set, will produce "dtype[::1]" instead of "dtype[dim]" for
|
|
71
|
+
array types.
|
|
72
|
+
|
|
73
|
+
add_dim:
|
|
74
|
+
|
|
75
|
+
Append a dim to the type, e.g., "int32_t[::1]" instead of
|
|
76
|
+
"int32_t" for dtype "int32". If this DType is already an array,
|
|
77
|
+
will create a 2D array, e.g., "int32_t[:, ::1]".
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
# is this an array type?
|
|
81
|
+
if self.is_array:
|
|
82
|
+
if add_dim:
|
|
83
|
+
suffix = "[:, ::1]"
|
|
84
|
+
else:
|
|
85
|
+
if use_memory_view:
|
|
86
|
+
suffix = "[::1]"
|
|
87
|
+
else:
|
|
88
|
+
suffix = f"[{self.size}]"
|
|
89
|
+
else:
|
|
90
|
+
suffix = "[::1]" if add_dim else ""
|
|
91
|
+
|
|
92
|
+
return self.base_c_type + suffix
|
|
93
|
+
|
|
94
|
+
def to_rvalue(self, name, array_index=None):
|
|
95
|
+
"""Convert this dtype into an r-value to be used in PYX files for
|
|
96
|
+
assignments.
|
|
97
|
+
|
|
98
|
+
"name" default
|
|
99
|
+
"name[array_index]" if array_index is given
|
|
100
|
+
"{name[0], ..., name[size-1]}"
|
|
101
|
+
if an array type
|
|
102
|
+
"{name[array_index, 0], ..., name[array_index, size-1]}"
|
|
103
|
+
if an array type and array_index is given
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
if self.is_array:
|
|
107
|
+
if array_index:
|
|
108
|
+
return (
|
|
109
|
+
"{"
|
|
110
|
+
+ ", ".join(
|
|
111
|
+
[name + f"[{array_index}, {i}]" for i in range(self.size)]
|
|
112
|
+
)
|
|
113
|
+
+ "}"
|
|
114
|
+
)
|
|
115
|
+
else:
|
|
116
|
+
return (
|
|
117
|
+
"{" + ", ".join([name + f"[{i}]" for i in range(self.size)]) + "}"
|
|
118
|
+
)
|
|
119
|
+
else:
|
|
120
|
+
if array_index:
|
|
121
|
+
return f"{name}[{array_index}]"
|
|
122
|
+
else:
|
|
123
|
+
return name
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def dtypes_to_struct(struct_name, dtypes):
|
|
127
|
+
pyx_code = f"cdef struct {struct_name}:\n"
|
|
128
|
+
for name, dtype in dtypes.items():
|
|
129
|
+
pyx_code += f" {dtype.to_pyxtype()} {name}\n"
|
|
130
|
+
return pyx_code
|