edsger 0.1.0__tar.gz → 0.1.2__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.
- {edsger-0.1.0 → edsger-0.1.2}/.github/workflows/publish.yml +4 -2
- edsger-0.1.2/.github/workflows/tests.yml +41 -0
- edsger-0.1.2/.pre-commit-config.yaml +14 -0
- edsger-0.1.2/PKG-INFO +118 -0
- edsger-0.1.2/README.md +77 -0
- {edsger-0.1.0 → edsger-0.1.2}/docs/source/api.md +0 -20
- edsger-0.1.2/docs/source/assets/dijkstra_benchmark_comparison.png +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/docs/source/conf.py +5 -4
- edsger-0.1.2/docs/source/index.md +80 -0
- {edsger-0.1.0 → edsger-0.1.2}/docs/source/quickstart.md +61 -31
- {edsger-0.1.0 → edsger-0.1.2}/pyproject.toml +11 -2
- {edsger-0.1.0 → edsger-0.1.2}/requirements-dev.txt +3 -0
- edsger-0.1.2/scripts/benchmark_comparison.py +442 -0
- {edsger-0.1.0 → edsger-0.1.2}/scripts/dijkstra_dimacs.py +4 -4
- edsger-0.1.2/scripts/requirements.txt +11 -0
- {edsger-0.1.0 → edsger-0.1.2}/setup.py +9 -3
- edsger-0.1.2/src/edsger/.gitignore +1 -0
- edsger-0.1.2/src/edsger/_version.py +1 -0
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/commons.c +156 -152
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/commons.pxd +6 -6
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/commons.pyx +4 -4
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/dijkstra.c +1188 -1115
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/dijkstra.pyx +94 -71
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/networks.py +1 -2
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/path.py +1 -1
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/path_tracking.c +152 -148
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/path_tracking.pyx +9 -9
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/pq_4ary_dec_0b.c +299 -295
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/pq_4ary_dec_0b.pxd +7 -7
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/pq_4ary_dec_0b.pyx +74 -76
- edsger-0.1.2/src/edsger/prefetch_compat.h +21 -0
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/spiess_florian.c +231 -250
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/spiess_florian.pyx +24 -24
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/star.c +194 -190
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/star.pyx +41 -41
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/utils.py +2 -2
- edsger-0.1.2/src/edsger.egg-info/PKG-INFO +118 -0
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger.egg-info/SOURCES.txt +6 -0
- {edsger-0.1.0 → edsger-0.1.2}/tests/test_dijkstra.py +7 -3
- {edsger-0.1.0 → edsger-0.1.2}/tests/test_path.py +1 -1
- {edsger-0.1.0 → edsger-0.1.2}/tests/test_path_tracking.py +1 -1
- {edsger-0.1.0 → edsger-0.1.2}/tests/test_pq_4ary_dec_0b.py +1 -1
- {edsger-0.1.0 → edsger-0.1.2}/tests/test_spiess_florian.py +1 -2
- edsger-0.1.0/.github/workflows/tests.yml +0 -28
- edsger-0.1.0/PKG-INFO +0 -279
- edsger-0.1.0/README.md +0 -243
- edsger-0.1.0/docs/source/index.md +0 -54
- edsger-0.1.0/src/edsger/_version.py +0 -1
- edsger-0.1.0/src/edsger.egg-info/PKG-INFO +0 -279
- {edsger-0.1.0 → edsger-0.1.2}/.github/workflows/docs.yml +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/.gitignore +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/.readthedocs.yaml +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/AUTHORS.rst +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/CHANGELOG.rst +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/CONTRIBUTING.rst +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/LICENSE +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/MANIFEST.in +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/docs/Makefile +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/docs/requirements.txt +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/docs/source/contributing.md +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/docs/source/installation.md +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/requirements.txt +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/setup.cfg +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger/__init__.py +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger.egg-info/dependency_links.txt +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger.egg-info/not-zip-safe +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger.egg-info/requires.txt +0 -0
- {edsger-0.1.0 → edsger-0.1.2}/src/edsger.egg-info/top_level.txt +0 -0
@@ -10,7 +10,7 @@ jobs:
|
|
10
10
|
strategy:
|
11
11
|
matrix:
|
12
12
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
13
|
-
python-version: ["3.11"]
|
13
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
14
14
|
runs-on: ${{ matrix.os }}
|
15
15
|
steps:
|
16
16
|
- uses: actions/checkout@v4
|
@@ -54,6 +54,7 @@ jobs:
|
|
54
54
|
|
55
55
|
- uses: actions/upload-artifact@v4
|
56
56
|
with:
|
57
|
+
name: cibw-sdist
|
57
58
|
path: ./dist/*.tar.gz
|
58
59
|
|
59
60
|
build_wheels:
|
@@ -95,7 +96,8 @@ jobs:
|
|
95
96
|
- name: Download all the dists
|
96
97
|
uses: actions/download-artifact@v4
|
97
98
|
with:
|
98
|
-
|
99
|
+
pattern: cibw-*
|
99
100
|
path: ./dist/
|
101
|
+
merge-multiple: true
|
100
102
|
- name: Publish distribution to PyPI
|
101
103
|
uses: pypa/gh-action-pypi-publish@release/v1
|
@@ -0,0 +1,41 @@
|
|
1
|
+
name: ci-test
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- release
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
test:
|
10
|
+
strategy:
|
11
|
+
matrix:
|
12
|
+
os: [ubuntu-22.04, windows-2022, macos-14]
|
13
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
14
|
+
runs-on: ${{ matrix.os }}
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v4
|
17
|
+
- name: Set up Python ${{ matrix.python-version }}
|
18
|
+
uses: actions/setup-python@v5
|
19
|
+
with:
|
20
|
+
python-version: ${{ matrix.python-version }}
|
21
|
+
- name: Install dependencies
|
22
|
+
run: |
|
23
|
+
python -m pip install --upgrade pip
|
24
|
+
pip install -r requirements-dev.txt
|
25
|
+
pip install .
|
26
|
+
- name: Format Python code with black
|
27
|
+
run: |
|
28
|
+
black --check --diff .
|
29
|
+
- name: Lint Cython code
|
30
|
+
run: |
|
31
|
+
cython-lint src/edsger/commons.pyx src/edsger/dijkstra.pyx src/edsger/path_tracking.pyx src/edsger/pq_4ary_dec_0b.pyx src/edsger/spiess_florian.pyx src/edsger/star.pyx src/edsger/commons.pxd src/edsger/pq_4ary_dec_0b.pxd
|
32
|
+
- name: Testing
|
33
|
+
run: |
|
34
|
+
python -m pytest --cov=src/edsger --cov-report=xml tests/
|
35
|
+
- name: Upload coverage to Codecov
|
36
|
+
uses: codecov/codecov-action@v4
|
37
|
+
with:
|
38
|
+
file: ./coverage.xml
|
39
|
+
flags: unittests
|
40
|
+
name: codecov-umbrella
|
41
|
+
fail_ci_if_error: false
|
@@ -0,0 +1,14 @@
|
|
1
|
+
repos:
|
2
|
+
- repo: https://github.com/psf/black
|
3
|
+
rev: 24.10.0
|
4
|
+
hooks:
|
5
|
+
- id: black
|
6
|
+
files: '\.(py)$'
|
7
|
+
exclude: 'src/edsger/.*\.pyx$'
|
8
|
+
|
9
|
+
- repo: https://github.com/MarcoGorelli/cython-lint
|
10
|
+
rev: v0.16.2
|
11
|
+
hooks:
|
12
|
+
- id: cython-lint
|
13
|
+
files: '\.(pyx|pxd)$'
|
14
|
+
args: [--max-line-length=88]
|
edsger-0.1.2/PKG-INFO
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: edsger
|
3
|
+
Version: 0.1.2
|
4
|
+
Summary: Graph algorithms in Cython.
|
5
|
+
Author-email: François Pacull <francois.pacull@architecture-performance.fr>
|
6
|
+
Maintainer-email: François Pacull <francois.pacull@architecture-performance.fr>
|
7
|
+
License: MIT License
|
8
|
+
Project-URL: Repository, https://github.com/aetperf/Edsger
|
9
|
+
Project-URL: Documentation, https://edsger.readthedocs.io
|
10
|
+
Keywords: python,graph,shortest path,Dijkstra
|
11
|
+
Platform: any
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
19
|
+
Classifier: License :: OSI Approved :: MIT License
|
20
|
+
Classifier: Operating System :: OS Independent
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
22
|
+
Requires-Python: >=3.9
|
23
|
+
Description-Content-Type: text/markdown
|
24
|
+
License-File: LICENSE
|
25
|
+
License-File: AUTHORS.rst
|
26
|
+
Requires-Dist: setuptools
|
27
|
+
Requires-Dist: setuptools_scm
|
28
|
+
Requires-Dist: numpy>=1.26
|
29
|
+
Requires-Dist: Cython>=3
|
30
|
+
Requires-Dist: pandas
|
31
|
+
Provides-Extra: dev
|
32
|
+
Requires-Dist: black; extra == "dev"
|
33
|
+
Provides-Extra: test
|
34
|
+
Requires-Dist: pytest; extra == "test"
|
35
|
+
Requires-Dist: scipy<1.11; extra == "test"
|
36
|
+
Provides-Extra: doc
|
37
|
+
Requires-Dist: sphinx; extra == "doc"
|
38
|
+
Requires-Dist: sphinx_design; extra == "doc"
|
39
|
+
Requires-Dist: sphinx_rtd_theme; extra == "doc"
|
40
|
+
Dynamic: license-file
|
41
|
+
|
42
|
+
|
43
|
+

|
44
|
+
[](https://codecov.io/gh/aetperf/edsger)
|
45
|
+
[](https://pypi.org/project/edsger/)
|
46
|
+
[](https://pepy.tech/project/edsger)
|
47
|
+
[](https://pypi.org/project/edsger/)
|
48
|
+
[](https://github.com/psf/black)
|
49
|
+
[](https://github.com/MarcoGorelli/cython-lint)
|
50
|
+
[](https://opensource.org/licenses/MIT)
|
51
|
+
|
52
|
+
# Edsger
|
53
|
+
|
54
|
+
*Graph algorithms in Cython*
|
55
|
+
|
56
|
+
Welcome to our Python library for graph algorithms. So far, the library only includes Dijkstra's algorithm but we should add a range of common path algorithms later. It is also open-source and easy to integrate with other Python libraries. To get started, simply install the library using pip, and import it into your Python project.
|
57
|
+
|
58
|
+
Documentation : [https://edsger.readthedocs.io/en/latest/](https://edsger.readthedocs.io/en/latest/)
|
59
|
+
|
60
|
+
## Small example : Dijkstra's Algorithm
|
61
|
+
|
62
|
+
To use Dijkstra's algorithm, you can import the `Dijkstra` class from the `path` module. The function takes a graph and a source node as input, and returns the shortest path from the source node to all other nodes in the graph.
|
63
|
+
|
64
|
+
```python
|
65
|
+
import pandas as pd
|
66
|
+
|
67
|
+
from edsger.path import Dijkstra
|
68
|
+
|
69
|
+
# Create a DataFrame with the edges of the graph
|
70
|
+
edges = pd.DataFrame({
|
71
|
+
'tail': [0, 0, 1, 2, 2, 3],
|
72
|
+
'head': [1, 2, 2, 3, 4, 4],
|
73
|
+
'weight': [1, 4, 2, 1.5, 3, 1]
|
74
|
+
})
|
75
|
+
edges
|
76
|
+
```
|
77
|
+
|
78
|
+
| | tail | head | weight |
|
79
|
+
|---:|-------:|-------:|---------:|
|
80
|
+
| 0 | 0 | 1 | 1.0 |
|
81
|
+
| 1 | 0 | 2 | 4.0 |
|
82
|
+
| 2 | 1 | 2 | 2.0 |
|
83
|
+
| 3 | 2 | 3 | 1.5 |
|
84
|
+
| 4 | 2 | 4 | 3.0 |
|
85
|
+
| 5 | 3 | 4 | 1.0 |
|
86
|
+
|
87
|
+
```python
|
88
|
+
# Initialize the Dijkstra object
|
89
|
+
dijkstra = Dijkstra(edges)
|
90
|
+
|
91
|
+
# Run the algorithm from a source vertex
|
92
|
+
shortest_paths = dijkstra.run(vertex_idx=0)
|
93
|
+
print("Shortest paths:", shortest_paths)
|
94
|
+
```
|
95
|
+
|
96
|
+
Shortest paths: [0. 1. 3. 4.5 5.5]
|
97
|
+
|
98
|
+
We get the shortest paths from the source node 0 to all other nodes in the graph. The output is an array with the shortest path length to each node. A path length is the sum of the weights of the edges in the path.
|
99
|
+
|
100
|
+
## Why Use Edsger?
|
101
|
+
|
102
|
+
Edsger is designed to be **dataframe-friendly**, providing seamless integration with pandas workflows for graph algorithms. Also it is rather efficient. Our benchmarks on the USA road network (23.9M vertices, 57.7M edges) demonstrate nice performance:
|
103
|
+
|
104
|
+
<img src="docs/source/assets/dijkstra_benchmark_comparison.png" alt="Dijkstra Performance Comparison" width="700">
|
105
|
+
|
106
|
+
*Benchmark performed on Intel i9-12900H laptop.*
|
107
|
+
|
108
|
+
## Contributing
|
109
|
+
|
110
|
+
We welcome contributions to the Edsger library. If you have any suggestions, bug reports, or feature requests, please open an issue on our [GitHub repository](https://github.com/aetperf/Edsger).
|
111
|
+
|
112
|
+
## License
|
113
|
+
|
114
|
+
Edsger is licensed under the MIT License. See the LICENSE file for more details.
|
115
|
+
|
116
|
+
## Contact
|
117
|
+
|
118
|
+
For any questions or inquiries, please contact François Pacull at [francois.pacull@architecture-performance.fr](mailto:francois.pacull@architecture-performance.fr).
|
edsger-0.1.2/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+

|
3
|
+
[](https://codecov.io/gh/aetperf/edsger)
|
4
|
+
[](https://pypi.org/project/edsger/)
|
5
|
+
[](https://pepy.tech/project/edsger)
|
6
|
+
[](https://pypi.org/project/edsger/)
|
7
|
+
[](https://github.com/psf/black)
|
8
|
+
[](https://github.com/MarcoGorelli/cython-lint)
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
10
|
+
|
11
|
+
# Edsger
|
12
|
+
|
13
|
+
*Graph algorithms in Cython*
|
14
|
+
|
15
|
+
Welcome to our Python library for graph algorithms. So far, the library only includes Dijkstra's algorithm but we should add a range of common path algorithms later. It is also open-source and easy to integrate with other Python libraries. To get started, simply install the library using pip, and import it into your Python project.
|
16
|
+
|
17
|
+
Documentation : [https://edsger.readthedocs.io/en/latest/](https://edsger.readthedocs.io/en/latest/)
|
18
|
+
|
19
|
+
## Small example : Dijkstra's Algorithm
|
20
|
+
|
21
|
+
To use Dijkstra's algorithm, you can import the `Dijkstra` class from the `path` module. The function takes a graph and a source node as input, and returns the shortest path from the source node to all other nodes in the graph.
|
22
|
+
|
23
|
+
```python
|
24
|
+
import pandas as pd
|
25
|
+
|
26
|
+
from edsger.path import Dijkstra
|
27
|
+
|
28
|
+
# Create a DataFrame with the edges of the graph
|
29
|
+
edges = pd.DataFrame({
|
30
|
+
'tail': [0, 0, 1, 2, 2, 3],
|
31
|
+
'head': [1, 2, 2, 3, 4, 4],
|
32
|
+
'weight': [1, 4, 2, 1.5, 3, 1]
|
33
|
+
})
|
34
|
+
edges
|
35
|
+
```
|
36
|
+
|
37
|
+
| | tail | head | weight |
|
38
|
+
|---:|-------:|-------:|---------:|
|
39
|
+
| 0 | 0 | 1 | 1.0 |
|
40
|
+
| 1 | 0 | 2 | 4.0 |
|
41
|
+
| 2 | 1 | 2 | 2.0 |
|
42
|
+
| 3 | 2 | 3 | 1.5 |
|
43
|
+
| 4 | 2 | 4 | 3.0 |
|
44
|
+
| 5 | 3 | 4 | 1.0 |
|
45
|
+
|
46
|
+
```python
|
47
|
+
# Initialize the Dijkstra object
|
48
|
+
dijkstra = Dijkstra(edges)
|
49
|
+
|
50
|
+
# Run the algorithm from a source vertex
|
51
|
+
shortest_paths = dijkstra.run(vertex_idx=0)
|
52
|
+
print("Shortest paths:", shortest_paths)
|
53
|
+
```
|
54
|
+
|
55
|
+
Shortest paths: [0. 1. 3. 4.5 5.5]
|
56
|
+
|
57
|
+
We get the shortest paths from the source node 0 to all other nodes in the graph. The output is an array with the shortest path length to each node. A path length is the sum of the weights of the edges in the path.
|
58
|
+
|
59
|
+
## Why Use Edsger?
|
60
|
+
|
61
|
+
Edsger is designed to be **dataframe-friendly**, providing seamless integration with pandas workflows for graph algorithms. Also it is rather efficient. Our benchmarks on the USA road network (23.9M vertices, 57.7M edges) demonstrate nice performance:
|
62
|
+
|
63
|
+
<img src="docs/source/assets/dijkstra_benchmark_comparison.png" alt="Dijkstra Performance Comparison" width="700">
|
64
|
+
|
65
|
+
*Benchmark performed on Intel i9-12900H laptop.*
|
66
|
+
|
67
|
+
## Contributing
|
68
|
+
|
69
|
+
We welcome contributions to the Edsger library. If you have any suggestions, bug reports, or feature requests, please open an issue on our [GitHub repository](https://github.com/aetperf/Edsger).
|
70
|
+
|
71
|
+
## License
|
72
|
+
|
73
|
+
Edsger is licensed under the MIT License. See the LICENSE file for more details.
|
74
|
+
|
75
|
+
## Contact
|
76
|
+
|
77
|
+
For any questions or inquiries, please contact François Pacull at [francois.pacull@architecture-performance.fr](mailto:francois.pacull@architecture-performance.fr).
|
@@ -114,23 +114,3 @@ paths = dijkstra.run(
|
|
114
114
|
heap_length_ratio=0.5
|
115
115
|
)
|
116
116
|
```
|
117
|
-
|
118
|
-
### Graph Data Format
|
119
|
-
|
120
|
-
Edsger expects graph data as a pandas DataFrame with the following structure:
|
121
|
-
|
122
|
-
| Column | Type | Description |
|
123
|
-
|--------|---------|--------------------------------------|
|
124
|
-
| tail | int | Source vertex ID |
|
125
|
-
| head | int | Destination vertex ID |
|
126
|
-
| weight | float | Edge weight (must be non-negative) |
|
127
|
-
|
128
|
-
Example:
|
129
|
-
```python
|
130
|
-
edges = pd.DataFrame({
|
131
|
-
'tail': [0, 0, 1, 2],
|
132
|
-
'head': [1, 2, 2, 3],
|
133
|
-
'weight': [1.0, 4.0, 2.0, 1.0]
|
134
|
-
})
|
135
|
-
```
|
136
|
-
|
Binary file
|
@@ -18,12 +18,13 @@ sys.path.insert(0, os.path.abspath("../../src/"))
|
|
18
18
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
19
19
|
|
20
20
|
project = "Edsger"
|
21
|
-
copyright = "
|
21
|
+
copyright = "2025, Architecture & Performance"
|
22
22
|
author = "Francois Pacull"
|
23
23
|
|
24
24
|
# Get version from the package
|
25
25
|
try:
|
26
26
|
from edsger._version import __version__
|
27
|
+
|
27
28
|
release = __version__
|
28
29
|
version = __version__
|
29
30
|
except ImportError:
|
@@ -69,6 +70,6 @@ myst_enable_extensions = [
|
|
69
70
|
|
70
71
|
# Source suffix
|
71
72
|
source_suffix = {
|
72
|
-
|
73
|
-
|
74
|
-
}
|
73
|
+
".rst": "restructuredtext",
|
74
|
+
".md": "markdown",
|
75
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
---
|
2
|
+
github_url: https://github.com/aetperf/Edsger
|
3
|
+
---
|
4
|
+
|
5
|
+
# Edsger
|
6
|
+
|
7
|
+
*Graph algorithms in Cython*
|
8
|
+
|
9
|
+
Welcome to the Edsger documentation! Edsger is a Python library for efficient graph algorithms implemented in Cython. The library currently focuses on shortest path algorithms, with Dijkstra's algorithm fully implemented and additional algorithms planned for future releases.
|
10
|
+
|
11
|
+
## Why Use Edsger?
|
12
|
+
|
13
|
+
Edsger is designed to be **dataframe-friendly**, providing seamless integration with pandas workflows for graph algorithms. Also it is rather efficient. Our benchmarks on the USA road network (23.9M vertices, 57.7M edges) demonstrate nice performance:
|
14
|
+
|
15
|
+
<img src="assets/dijkstra_benchmark_comparison.png" alt="Dijkstra Performance Comparison" width="700">
|
16
|
+
|
17
|
+
*Benchmark performed on Intel i9-12900H laptop.*
|
18
|
+
|
19
|
+
### Pandas Integration Made Simple
|
20
|
+
|
21
|
+
```python
|
22
|
+
import pandas as pd
|
23
|
+
from edsger.path import Dijkstra
|
24
|
+
|
25
|
+
# Your graph data is already in a DataFrame
|
26
|
+
edges = pd.DataFrame({
|
27
|
+
'tail': [0, 0, 1, 2],
|
28
|
+
'head': [1, 2, 2, 3],
|
29
|
+
'weight': [1.0, 2.0, 1.5, 1.0]
|
30
|
+
})
|
31
|
+
|
32
|
+
# No conversion needed - use directly!
|
33
|
+
dijkstra = Dijkstra(edges, orientation="out")
|
34
|
+
distances = dijkstra.run(vertex_idx=0)
|
35
|
+
```
|
36
|
+
|
37
|
+
## Key Features
|
38
|
+
|
39
|
+
- **Native pandas DataFrame support** - No graph object conversion required
|
40
|
+
- **High performance** - Cython implementation with aggressive optimizations
|
41
|
+
- **Memory efficient** - Optimized for large-scale real-world datasets
|
42
|
+
- **Easy integration** with NumPy and pandas workflows
|
43
|
+
- **Production ready** - Comprehensive testing across Python 3.9-3.13
|
44
|
+
|
45
|
+
## Quick Links
|
46
|
+
|
47
|
+
- [Installation](installation.md) - How to install Edsger
|
48
|
+
- [Quick Start](quickstart.md) - Get started quickly with basic examples
|
49
|
+
- [API Reference](api.md) - Complete API reference
|
50
|
+
|
51
|
+
## Table of Contents
|
52
|
+
|
53
|
+
```{toctree}
|
54
|
+
:maxdepth: 2
|
55
|
+
:caption: User Guide
|
56
|
+
|
57
|
+
installation
|
58
|
+
quickstart
|
59
|
+
```
|
60
|
+
|
61
|
+
```{toctree}
|
62
|
+
:maxdepth: 2
|
63
|
+
:caption: API Reference
|
64
|
+
|
65
|
+
api
|
66
|
+
```
|
67
|
+
|
68
|
+
```{toctree}
|
69
|
+
:maxdepth: 1
|
70
|
+
:caption: Development
|
71
|
+
|
72
|
+
contributing
|
73
|
+
```
|
74
|
+
|
75
|
+
## Indices
|
76
|
+
|
77
|
+
- {ref}`genindex`
|
78
|
+
- {ref}`modindex`
|
79
|
+
- {ref}`search`
|
80
|
+
|
@@ -2,22 +2,27 @@
|
|
2
2
|
|
3
3
|
Welcome to our Python library for graph algorithms. So far, the library only includes Dijkstra's algorithm but we should add a range of common path algorithms later. It is also open-source and easy to integrate with other Python libraries.
|
4
4
|
|
5
|
-
## Dijkstra's Algorithm
|
6
5
|
|
7
|
-
|
6
|
+
## Graph Data Format
|
7
|
+
|
8
|
+
Edsger expects graph data as a pandas DataFrame with the following structure:
|
9
|
+
|
10
|
+
| Column | Type | Description |
|
11
|
+
|--------|---------|--------------------------------------|
|
12
|
+
| tail | int | Source vertex ID |
|
13
|
+
| head | int | Destination vertex ID |
|
14
|
+
| weight | float | Edge weight (must be non-negative) |
|
8
15
|
|
16
|
+
Example:
|
9
17
|
```python
|
10
18
|
import pandas as pd
|
11
19
|
|
12
|
-
from edsger.path import Dijkstra
|
13
|
-
|
14
|
-
# Create a DataFrame with the edges of the graph
|
15
20
|
edges = pd.DataFrame({
|
16
|
-
'tail': [0, 0, 1, 2
|
17
|
-
'head': [1, 2, 2, 3
|
18
|
-
'weight': [1, 4, 2, 1
|
21
|
+
'tail': [0, 0, 1, 2],
|
22
|
+
'head': [1, 2, 2, 3],
|
23
|
+
'weight': [1.0, 4.0, 2.0, 1.0]
|
19
24
|
})
|
20
|
-
|
25
|
+
edsges
|
21
26
|
```
|
22
27
|
|
23
28
|
| | tail | head | weight |
|
@@ -26,8 +31,32 @@ edges
|
|
26
31
|
| 1 | 0 | 2 | 4 |
|
27
32
|
| 2 | 1 | 2 | 2 |
|
28
33
|
| 3 | 2 | 3 | 1 |
|
29
|
-
|
30
|
-
|
34
|
+
|
35
|
+
|
36
|
+
## Dijkstra's Algorithm
|
37
|
+
|
38
|
+
To use Dijkstra's algorithm, you can import the `Dijkstra` class from the `path` module. The function takes a graph and a source node as input, and returns the shortest path from the source node to all other nodes in the graph.
|
39
|
+
|
40
|
+
```python
|
41
|
+
from edsger.path import Dijkstra
|
42
|
+
|
43
|
+
# Create a DataFrame with the edges of the graph
|
44
|
+
edges = pd.DataFrame({
|
45
|
+
'tail': [0, 0, 1, 2, 2, 3],
|
46
|
+
'head': [1, 2, 2, 3, 4, 4],
|
47
|
+
'weight': [1, 4, 2, 1.5, 3, 1]
|
48
|
+
})
|
49
|
+
edges
|
50
|
+
```
|
51
|
+
|
52
|
+
| | tail | head | weight |
|
53
|
+
|---:|-------:|-------:|---------:|
|
54
|
+
| 0 | 0 | 1 | 1.0 |
|
55
|
+
| 1 | 0 | 2 | 4.0 |
|
56
|
+
| 2 | 1 | 2 | 2.0 |
|
57
|
+
| 3 | 2 | 3 | 1.5 |
|
58
|
+
| 4 | 2 | 4 | 3.0 |
|
59
|
+
| 5 | 3 | 4 | 1.0 |
|
31
60
|
|
32
61
|
|
33
62
|
```python
|
@@ -39,7 +68,7 @@ shortest_paths = dijkstra.run(vertex_idx=0)
|
|
39
68
|
print("Shortest paths:", shortest_paths)
|
40
69
|
```
|
41
70
|
|
42
|
-
Shortest paths: [0.
|
71
|
+
Shortest paths: [0. 1. 3. 4.5 5.5]
|
43
72
|
|
44
73
|
We get the shortest paths from the source node 0 to all other nodes in the graph. The output is an array with the shortest path length to each node. A path length is the sum of the weights of the edges in the path.
|
45
74
|
|
@@ -49,12 +78,12 @@ It is also possible to use a graph with different column names for the tail, hea
|
|
49
78
|
other_edges = pd.DataFrame({
|
50
79
|
'from': [0, 0, 1, 2, 2, 3],
|
51
80
|
'to': [1, 2, 2, 3, 4, 4],
|
52
|
-
'travel_time': [1, 4, 2, 1, 3, 1]
|
81
|
+
'travel_time': [1, 4, 2, 1.5, 3, 1]
|
53
82
|
})
|
54
|
-
other_dijkstra = Dijkstra(
|
83
|
+
other_dijkstra = Dijkstra(other_edges, tail='from', head='to', weight='travel_time')
|
55
84
|
```
|
56
85
|
|
57
|
-
|
86
|
+
### Orientation
|
58
87
|
|
59
88
|
The `orientation` argument (a string with a default value of `'out'`) specifies the orientation of the algorithm. It can be either `'out'` for single source shortest paths or `'in'` for single target shortest path.
|
60
89
|
|
@@ -68,7 +97,7 @@ print("Shortest paths:", shortest_paths)
|
|
68
97
|
|
69
98
|
Shortest paths: [ 0. inf inf inf inf]
|
70
99
|
|
71
|
-
|
100
|
+
### Run Multiple Times
|
72
101
|
|
73
102
|
Once the Dijkstra is instantiated with a given graph and orientation, the `run` method can be called multiple times with different source vertices.
|
74
103
|
|
@@ -78,9 +107,9 @@ shortest_paths = dijkstra.run(vertex_idx=4)
|
|
78
107
|
print("Shortest paths:", shortest_paths)
|
79
108
|
```
|
80
109
|
|
81
|
-
Shortest paths: [5. 4. 2. 1.
|
110
|
+
Shortest paths: [5.5 4.5 2.5 1. 0. ]
|
82
111
|
|
83
|
-
|
112
|
+
### Check Edges
|
84
113
|
|
85
114
|
The `check_edges` argument (a boolean with a default value of `False`) validates the given graph. When set to `True`, it ensures the DataFrame is well-formed by:
|
86
115
|
|
@@ -101,7 +130,7 @@ dijkstra = Dijkstra(invalid_edges, check_edges=True)
|
|
101
130
|
|
102
131
|
ValueError: edges['weight'] should be nonnegative
|
103
132
|
|
104
|
-
|
133
|
+
### Permute
|
105
134
|
|
106
135
|
Finally, the `permute` argument (boolean with a default value of `False`) allows to permute the IDs of the nodes. If set to `True`, the node IDs will be reindexed to start from 0 and be contiguous for the inner computations, and the output will be reindexed to the original IDs, loading the same result as if the IDs were not permuted. The permutation may save memory and computation time for large graphs, for example if a significant ratio of the nodes are not actually used in the graph.
|
107
136
|
|
@@ -111,7 +140,7 @@ SHIFT = 1000
|
|
111
140
|
shifted_edges = pd.DataFrame({
|
112
141
|
'tail': [0, 0, 1, 2, 2, 3],
|
113
142
|
'head': [1, 2, 2, 3, 4, 4],
|
114
|
-
'weight': [1, 4, 2, 1, 3, 1]
|
143
|
+
'weight': [1, 4, 2, 1.5, 3, 1]
|
115
144
|
})
|
116
145
|
shifted_edges["tail"] += SHIFT
|
117
146
|
shifted_edges["head"] += SHIFT
|
@@ -120,9 +149,9 @@ shifted_edges.head(3)
|
|
120
149
|
|
121
150
|
| | tail | head | weight |
|
122
151
|
|---:|-------:|-------:|---------:|
|
123
|
-
| 0 | 1000 | 1001 |
|
124
|
-
| 1 | 1000 | 1002 |
|
125
|
-
| 2 | 1001 | 1002 |
|
152
|
+
| 0 | 1000 | 1001 | 1.0 |
|
153
|
+
| 1 | 1000 | 1002 | 4.0 |
|
154
|
+
| 2 | 1001 | 1002 | 2.0 |
|
126
155
|
|
127
156
|
|
128
157
|
|
@@ -132,15 +161,16 @@ shortest_paths = dijkstra.run(vertex_idx=0 + SHIFT)
|
|
132
161
|
print("Shortest paths:", shortest_paths)
|
133
162
|
```
|
134
163
|
|
135
|
-
Shortest paths: [inf inf inf ...
|
164
|
+
Shortest paths: [inf inf inf ... 3. 4.5 5.5]
|
136
165
|
|
137
166
|
```python
|
138
167
|
shortest_paths[-5:]
|
139
168
|
```
|
140
169
|
|
141
|
-
array([0
|
170
|
+
array([0. , 1. , 3. , 4.5, 5.5])
|
171
|
+
|
142
172
|
|
143
|
-
|
173
|
+
### Run Method Options
|
144
174
|
|
145
175
|
The `run` method can take the following arguments besides the source/target vertex index:
|
146
176
|
|
@@ -190,11 +220,11 @@ shortest_paths
|
|
190
220
|
|
191
221
|
| vertex_idx | path_length |
|
192
222
|
|-------------:|--------------:|
|
193
|
-
| 0 |
|
194
|
-
| 1 |
|
195
|
-
| 2 |
|
196
|
-
| 3 |
|
197
|
-
| 4 |
|
223
|
+
| 0 | 5.5 |
|
224
|
+
| 1 | 4.5 |
|
225
|
+
| 2 | 2.5 |
|
226
|
+
| 3 | 1.0 |
|
227
|
+
| 4 | 0.0 |
|
198
228
|
|
199
229
|
|
200
230
|
- `heap_length_ratio` : float, optional (default=1.0)
|
@@ -7,7 +7,7 @@ name = "edsger"
|
|
7
7
|
dynamic = ["version"]
|
8
8
|
description = "Graph algorithms in Cython."
|
9
9
|
readme = "README.md"
|
10
|
-
requires-python = ">=3.
|
10
|
+
requires-python = ">=3.9"
|
11
11
|
license = {text = "MIT License"}
|
12
12
|
authors = [
|
13
13
|
{ name = "François Pacull", email = "francois.pacull@architecture-performance.fr" },
|
@@ -19,6 +19,11 @@ keywords = ["python", "graph", "shortest path", "Dijkstra"]
|
|
19
19
|
classifiers = [
|
20
20
|
"Development Status :: 4 - Beta",
|
21
21
|
"Programming Language :: Python :: 3",
|
22
|
+
"Programming Language :: Python :: 3.9",
|
23
|
+
"Programming Language :: Python :: 3.10",
|
24
|
+
"Programming Language :: Python :: 3.11",
|
25
|
+
"Programming Language :: Python :: 3.12",
|
26
|
+
"Programming Language :: Python :: 3.13",
|
22
27
|
"License :: OSI Approved :: MIT License",
|
23
28
|
"Operating System :: OS Independent",
|
24
29
|
"Topic :: Scientific/Engineering"
|
@@ -61,4 +66,8 @@ write_to_template = '__version__ = "{version}"'
|
|
61
66
|
[tool.pytest.ini_options]
|
62
67
|
testpaths = [
|
63
68
|
"tests"
|
64
|
-
]
|
69
|
+
]
|
70
|
+
|
71
|
+
[tool.cibuildwheel]
|
72
|
+
# Skip 32-bit i686 architectures (outdated, rarely needed)
|
73
|
+
skip = "*_i686"
|