pyastar2d 1.1.0__cp38-abi3-musllinux_1_2_x86_64.whl

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.
pyastar2d/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from pyastar2d.astar_wrapper import Heuristic, astar_path
2
+
3
+ __all__ = ['astar_path', 'Heuristic']
Binary file
@@ -0,0 +1,77 @@
1
+ import ctypes
2
+ from enum import IntEnum
3
+ from typing import Optional, Tuple
4
+
5
+ import numpy as np
6
+
7
+ import pyastar2d.astar
8
+
9
+ # Define array types
10
+ ndmat_f_type = np.ctypeslib.ndpointer(dtype=np.float32, ndim=1, flags='C_CONTIGUOUS')
11
+ ndmat_i2_type = np.ctypeslib.ndpointer(dtype=np.int32, ndim=2, flags='C_CONTIGUOUS')
12
+
13
+ # Define input/output types
14
+ pyastar2d.astar.restype = ndmat_i2_type # Nx2 (i, j) coordinates or None
15
+ pyastar2d.astar.argtypes = [
16
+ ndmat_f_type, # weights
17
+ ctypes.c_int, # height
18
+ ctypes.c_int, # width
19
+ ctypes.c_int, # start index in flattened grid
20
+ ctypes.c_int, # goal index in flattened grid
21
+ ctypes.c_bool, # allow diagonal
22
+ ctypes.c_int, # heuristic_override
23
+ ]
24
+
25
+
26
+ class Heuristic(IntEnum):
27
+ """The supported heuristics."""
28
+
29
+ DEFAULT = 0
30
+ ORTHOGONAL_X = 1
31
+ ORTHOGONAL_Y = 2
32
+
33
+
34
+ def astar_path(
35
+ weights: np.ndarray,
36
+ start: Tuple[int, int],
37
+ goal: Tuple[int, int],
38
+ allow_diagonal: bool = False,
39
+ heuristic_override: Heuristic = Heuristic.DEFAULT,
40
+ ) -> Optional[np.ndarray]:
41
+ """
42
+ Run astar algorithm on 2d weights.
43
+
44
+ param np.ndarray weights: A grid of weights e.g. np.ones((10, 10), dtype=np.float32)
45
+ param Tuple[int, int] start: (i, j)
46
+ param Tuple[int, int] goal: (i, j)
47
+ param bool allow_diagonal: Whether to allow diagonal moves
48
+ param Heuristic heuristic_override: Override heuristic, see Heuristic(IntEnum)
49
+
50
+ """
51
+ assert (
52
+ weights.dtype == np.float32
53
+ ), f'weights must have np.float32 data type, but has {weights.dtype}'
54
+ # For the heuristic to be valid, each move must cost at least 1.
55
+ if weights.min(axis=None) < 1.0:
56
+ raise ValueError('Minimum cost to move must be 1, but got %f' % (weights.min(axis=None)))
57
+ # Ensure start is within bounds.
58
+ if start[0] < 0 or start[0] >= weights.shape[0] or start[1] < 0 or start[1] >= weights.shape[1]:
59
+ raise ValueError(f'Start of {start} lies outside grid.')
60
+ # Ensure goal is within bounds.
61
+ if goal[0] < 0 or goal[0] >= weights.shape[0] or goal[1] < 0 or goal[1] >= weights.shape[1]:
62
+ raise ValueError(f'Goal of {goal} lies outside grid.')
63
+
64
+ height, width = weights.shape
65
+ start_idx = np.ravel_multi_index(start, (height, width))
66
+ goal_idx = np.ravel_multi_index(goal, (height, width))
67
+
68
+ path = pyastar2d.astar.astar(
69
+ weights.flatten(),
70
+ height,
71
+ width,
72
+ start_idx,
73
+ goal_idx,
74
+ allow_diagonal,
75
+ int(heuristic_override),
76
+ )
77
+ return path
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Hendrik Weideman
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,194 @@
1
+ Metadata-Version: 2.1
2
+ Name: pyastar2d
3
+ Version: 1.1.0
4
+ Summary: A simple implementation of the A* algorithm for path-finding on a two-dimensional grid.
5
+ Home-page: https://github.com/hjweide/pyastar2d
6
+ Author: Hendrik Weideman
7
+ Author-email: hjweide@gmail.com
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: imageio
12
+ Requires-Dist: numpy
13
+
14
+ [![Build Status](https://travis-ci.com/hjweide/pyastar2d.svg?branch=master)](https://travis-ci.com/hjweide/pyastar2d)
15
+ [![Coverage Status](https://coveralls.io/repos/github/hjweide/pyastar2d/badge.svg?branch=master)](https://coveralls.io/github/hjweide/pyastar2d?branch=master)
16
+ [![PyPI version](https://badge.fury.io/py/pyastar2d.svg)](https://badge.fury.io/py/pyastar2d)
17
+ # PyAstar2D
18
+ This is a very simple C++ implementation of the A\* algorithm for pathfinding
19
+ on a two-dimensional grid. The solver itself is implemented in C++, but is
20
+ callable from Python. This combines the speed of C++ with the convenience of
21
+ Python.
22
+
23
+ I have not done any formal benchmarking, but the solver finds the solution to a
24
+ 1802 by 1802 maze in 0.29s and a 4008 by 4008 maze in 0.83s when running on my
25
+ nine-year-old Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz. See [Example
26
+ Results](#example-results) for more details.
27
+
28
+ See `src/cpp/astar.cpp` for the core C++ implementation of the A\* shortest
29
+ path search algorithm, `src/pyastar2d/astar_wrapper.py` for the Python wrapper
30
+ and `examples/example.py` for example usage.
31
+
32
+ When determining legal moves, 4-connectivity is the default, but it is possible
33
+ to set `allow_diagonal=True` for 8-connectivity.
34
+
35
+ ## Installation
36
+ Instructions for installing `pyastar2d` are given below.
37
+
38
+ ### From PyPI
39
+ The easiest way to install `pyastar2d` is directly from the Python package index:
40
+ ```
41
+ pip install pyastar2d
42
+ ```
43
+
44
+ ### From source
45
+ You can also install `pyastar2d` by cloning this repository and building it
46
+ yourself. If running on Linux or MacOS, simply run
47
+ ```bash
48
+ pip install .
49
+ ````
50
+ from the root directory. If you are using Windows you may have to install Cython manually first:
51
+ ```bash
52
+ pip install Cython
53
+ pip install .
54
+ ```
55
+ To check that everything worked, run the example:
56
+ ```bash
57
+ python examples/example.py
58
+ ```
59
+
60
+ ### As a dependency
61
+ Include `pyastar2d` in your `requirements.txt` to install from `pypi`, or add
62
+ this line to `requirements.txt`:
63
+ ```
64
+ pyastar2d @ git+git://github.com/hjweide/pyastar2d.git@master#egg=pyastar2d
65
+ ```
66
+
67
+ ## Usage
68
+ A simple example is given below:
69
+ ```python
70
+ import numpy as np
71
+ import pyastar2d
72
+ # The minimum cost must be 1 for the heuristic to be valid.
73
+ # The weights array must have np.float32 dtype to be compatible with the C++ code.
74
+ weights = np.array([[1, 3, 3, 3, 3],
75
+ [2, 1, 3, 3, 3],
76
+ [2, 2, 1, 3, 3],
77
+ [2, 2, 2, 1, 3],
78
+ [2, 2, 2, 2, 1]], dtype=np.float32)
79
+ # The start and goal coordinates are in matrix coordinates (i, j).
80
+ path = pyastar2d.astar_path(weights, (0, 0), (4, 4), allow_diagonal=True)
81
+ print(path)
82
+ # The path is returned as a numpy array of (i, j) coordinates.
83
+ array([[0, 0],
84
+ [1, 1],
85
+ [2, 2],
86
+ [3, 3],
87
+ [4, 4]])
88
+ ```
89
+ Note that all grid points are represented as `(i, j)` coordinates. An example
90
+ of using `pyastar2d` to solve a maze is given in `examples/maze_solver.py`.
91
+
92
+ ## Example Results
93
+ <a name="example-results"></a>
94
+ To test the implementation, I grabbed two nasty mazes from Wikipedia. They are
95
+ included in the ```mazes``` directory, but are originally from here:
96
+ [Small](https://upload.wikimedia.org/wikipedia/commons/c/cf/MAZE.png) and
97
+ [Large](https://upload.wikimedia.org/wikipedia/commons/3/32/MAZE_2000x2000_DFS.png).
98
+ I load the ```.png``` files as grayscale images, and set the white pixels to 1
99
+ (open space) and the black pixels to `INF` (walls).
100
+
101
+ To run the examples specify the input and output files using the `--input` and
102
+ `--output` flags. For example, the following commands will solve the small and
103
+ large mazes:
104
+ ```
105
+ python examples/maze_solver.py --input mazes/maze_small.png --output solns/maze_small.png
106
+ python examples/maze_solver.py --input mazes/maze_large.png --output solns/maze_large.png
107
+ ```
108
+
109
+ ### Small Maze (1802 x 1802):
110
+ ```bash
111
+ time python examples/maze_solver.py --input mazes/maze_small.png --output solns/maze_small.png
112
+ Loaded maze of shape (1802, 1802) from mazes/maze_small.png
113
+ Found path of length 10032 in 0.292794s
114
+ Plotting path to solns/maze_small.png
115
+ Done
116
+
117
+ real 0m1.214s
118
+ user 0m1.526s
119
+ sys 0m0.606s
120
+ ```
121
+ The solution found for the small maze is shown below:
122
+ <img src="https://github.com/hjweide/pyastar2d/raw/master/solns/maze_small_soln.png" alt="Maze Small Solution" style="width: 100%"/>
123
+
124
+ ### Large Maze (4002 x 4002):
125
+ ```bash
126
+ time python examples/maze_solver.py --input mazes/maze_large.png --output solns/maze_large.png
127
+ Loaded maze of shape (4002, 4002) from mazes/maze_large.png
128
+ Found path of length 783737 in 0.829181s
129
+ Plotting path to solns/maze_large.png
130
+ Done
131
+
132
+ real 0m29.385s
133
+ user 0m29.563s
134
+ sys 0m0.728s
135
+ ```
136
+ The solution found for the large maze is shown below:
137
+ <img src="https://github.com/hjweide/pyastar2d/raw/master/solns/maze_large_soln.png" alt="Maze Large Solution" style="width: 100%"/>
138
+
139
+ ## Motivation
140
+ I recently needed an implementation of the A* algorithm in Python to find the
141
+ shortest path between two points in a cost matrix representing an image.
142
+ Normally I would simply use [networkx](https://networkx.github.io/), but for
143
+ graphs with millions of nodes the overhead incurred to construct the graph can
144
+ be expensive. Considering that I was only interested in graphs that may be
145
+ represented as two-dimensional grids, I decided to implement it myself using
146
+ this special structure of the graph to make various optimizations.
147
+ Specifically, the graph is represented as a one-dimensional array because there
148
+ is no need to store the neighbors. Additionally, the lookup tables for
149
+ previously-explored nodes (their costs and paths) are also stored as
150
+ one-dimensional arrays. The implication of this is that checking the lookup
151
+ table can be done in O(1), at the cost of using O(n) memory. Alternatively, we
152
+ could store only the nodes we traverse in a hash table to reduce the memory
153
+ usage. Empirically I found that replacing the one-dimensional array with a
154
+ hash table (`std::unordered_map`) was about five times slower.
155
+
156
+ ## Tests
157
+ The default installation does not include the dependencies necessary to run the
158
+ tests. To install these, first run
159
+ ```bash
160
+ pip install -r requirements-dev.txt
161
+ ```
162
+ before running
163
+ ```bash
164
+ pytest
165
+ ```
166
+ The tests are fairly basic but cover some of the
167
+ more common pitfalls. Pull requests for more extensive tests are welcome.
168
+
169
+ ## Code Formatting
170
+
171
+ It's recommended that you use `pre-commit` to ensure linting procedures are
172
+ run on any code you write. See [pre-commit.com](https://pre-commit.com/) for
173
+ more information.
174
+
175
+ Reference [pre-commit's installation instructions](https://pre-commit.com/#install)
176
+ for software installation on your OS/platform. After you have the software
177
+ installed, run `pre-commit install` on the command line. Now every time you commit
178
+ to this project's code base the linter procedures will automatically run over the
179
+ changed files. To run pre-commit on files preemtively from the command line use:
180
+
181
+ ```bash
182
+ pip install -r requirements-dev.txt
183
+ pre-commit run --all-files
184
+ ```
185
+
186
+ The code base has been formatted by [Black](https://black.readthedocs.io/en/stable/).
187
+ Furthermore, try to conform to `PEP8`. You should set up your preferred editor to
188
+ use `flake8` as its Python linter, but pre-commit will ensure compliance before a
189
+ git commit is completed. This will use the `flake8` configuration within
190
+ `.flake8`, which ignores several errors and stylistic considerations.
191
+
192
+ ## References
193
+ 1. [A\* search algorithm on Wikipedia](https://en.wikipedia.org/wiki/A*_search_algorithm#Pseudocode)
194
+ 2. [Pathfinding with A* on Red Blob Games](http://www.redblobgames.com/pathfinding/a-star/introduction.html)
@@ -0,0 +1,11 @@
1
+ pyastar2d/__init__.py,sha256=_llpDHJfo_fzVW08m991vBF7Xeo_TfsdY3lbEPAmPog,97
2
+ pyastar2d/astar.abi3.so,sha256=FnxN-gk5fU7xUwRs5hdAxsGmS_WKf9AjMB1X9x_LH5w,124153
3
+ pyastar2d/astar_wrapper.py,sha256=tMXFGWQnq5wXSZs4LiaCfUBYUkoke7jTOvEEcxBURLU,2505
4
+ pyastar2d.libs/libgcc_s-0cd532bd.so.1,sha256=yPk0-VjyKzucjnkP3mvC0vVaua6Ln17qZUJbICcXgtA,181737
5
+ pyastar2d.libs/libstdc++-5d72f927.so.6.0.33,sha256=fogxHsmB1_D6C-a_-uHh8Ei_6Qh52a8vLlicJRM3ehk,3562401
6
+ pyastar2d-1.1.0.dist-info/LICENSE,sha256=XKV3_2Un6l3Wj3fAb8Q_olyi5s3AfI_NqG98vbLGqgs,1073
7
+ pyastar2d-1.1.0.dist-info/METADATA,sha256=G8lTlzXB5CL5zQPdVHYbTiOAEhDhhn7SVPHnIpPuEro,7961
8
+ pyastar2d-1.1.0.dist-info/WHEEL,sha256=GNKVx_vTTuZH97XJ5PMgbD9lX-qQXecS6Ik7HW3K0ng,110
9
+ pyastar2d-1.1.0.dist-info/top_level.txt,sha256=sirwTJoF4I2DthdhahGwb3hQxZRT8XbOhsNRdorJmXM,10
10
+ pyastar2d-1.1.0.dist-info/RECORD,,
11
+ pyastar2d-1.1.0.dist-info/sboms/auditwheel.cdx.json,sha256=4qd2TBbUTQtsY8oFCpVhRm5wAi1-CB5nmUf-YQK5bO0,1692
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.3.3)
3
+ Root-Is-Purelib: false
4
+ Tag: cp38-abi3-musllinux_1_2_x86_64
5
+
@@ -0,0 +1 @@
1
+ {"bomFormat": "CycloneDX", "specVersion": "1.4", "version": 1, "metadata": {"component": {"type": "library", "bom-ref": "pkg:pypi/pyastar2d@1.1.0?file_name=pyastar2d-1.1.0-cp38-abi3-musllinux_1_2_x86_64.whl", "name": "pyastar2d", "version": "1.1.0", "purl": "pkg:pypi/pyastar2d@1.1.0?file_name=pyastar2d-1.1.0-cp38-abi3-musllinux_1_2_x86_64.whl"}, "tools": [{"name": "auditwheel", "version": "6.5.0"}]}, "components": [{"type": "library", "bom-ref": "pkg:pypi/pyastar2d@1.1.0?file_name=pyastar2d-1.1.0-cp38-abi3-musllinux_1_2_x86_64.whl", "name": "pyastar2d", "version": "1.1.0", "purl": "pkg:pypi/pyastar2d@1.1.0?file_name=pyastar2d-1.1.0-cp38-abi3-musllinux_1_2_x86_64.whl"}, {"type": "library", "bom-ref": "pkg:apk/alpine/libstdc%2B%2B@14.2.0-r6#76f023cbc3d7b369d6008f354e88aa983d13e4bd8f06e4e49a01686039fe1509", "name": "libstdc++", "version": "14.2.0-r6", "purl": "pkg:apk/alpine/libstdc%2B%2B@14.2.0-r6"}, {"type": "library", "bom-ref": "pkg:apk/alpine/libgcc@14.2.0-r6#933a623c9e323e83b1734e630a342f206999adc096732a3fea9896fa0181ea29", "name": "libgcc", "version": "14.2.0-r6", "purl": "pkg:apk/alpine/libgcc@14.2.0-r6"}], "dependencies": [{"ref": "pkg:pypi/pyastar2d@1.1.0?file_name=pyastar2d-1.1.0-cp38-abi3-musllinux_1_2_x86_64.whl", "dependsOn": ["pkg:apk/alpine/libstdc%2B%2B@14.2.0-r6#76f023cbc3d7b369d6008f354e88aa983d13e4bd8f06e4e49a01686039fe1509", "pkg:apk/alpine/libgcc@14.2.0-r6#933a623c9e323e83b1734e630a342f206999adc096732a3fea9896fa0181ea29"]}, {"ref": "pkg:apk/alpine/libstdc%2B%2B@14.2.0-r6#76f023cbc3d7b369d6008f354e88aa983d13e4bd8f06e4e49a01686039fe1509"}, {"ref": "pkg:apk/alpine/libgcc@14.2.0-r6#933a623c9e323e83b1734e630a342f206999adc096732a3fea9896fa0181ea29"}]}
@@ -0,0 +1 @@
1
+ pyastar2d
Binary file