An extensible search algorithm framework for discrete spaces. Implements A*, BFS, DFS, Dijkstra and Bidirectional Search for graphs and grids.
Project description
search-library
An extensible search algorithm framework for discrete spaces. Designed as both a production-ready library and an academic reference implementation for graph search algorithms in artificial intelligence.
Motivation
Search algorithms are fundamental to artificial intelligence and computer science. From pathfinding in video games to route planning in logistics, from puzzle solving to knowledge graph traversal, the ability to efficiently explore state spaces is a core capability.
This library was built to:
- Provide correct, well-tested implementations of classical search algorithms
- Serve as a reference for students and researchers studying AI search
- Offer a unified API that enables fair comparison between algorithms
- Demonstrate software engineering best practices in algorithm library design
Algorithms
| Algorithm | Strategy | Optimal | Complete | Time | Space |
|---|---|---|---|---|---|
| A* | Best-first (f = g + h) | Yes (admissible h) | Yes | O(b^d) | O(b^d) |
| BFS | Level-order (FIFO) | Yes (unweighted) | Yes | O(V + E) | O(V) |
| DFS | Depth-first (LIFO) | No | Yes (finite) | O(V + E) | O(bm) |
| Dijkstra | Best-first (g only) | Yes | Yes | O((V+E) log V) | O(V) |
| Bidirectional | Dual BFS | Yes (unweighted) | Yes | O(b^(d/2)) | O(b^(d/2)) |
Where: b = branching factor, d = solution depth, m = max depth, V = vertices, E = edges.
A* Search
Informed search using f(n) = g(n) + h(n). Guarantees optimal paths when the heuristic is admissible (never overestimates). The most efficient algorithm when a good heuristic is available.
Breadth-First Search (BFS)
Explores nodes level by level. Guarantees the shortest path by edge count in unweighted graphs. Ideal when all transitions have equal cost.
Depth-First Search (DFS)
Explores as deep as possible before backtracking. Uses minimal memory but does not guarantee optimal paths. Useful for existence checks and exhaustive exploration.
Dijkstra's Algorithm
Equivalent to A* with h(n) = 0. Finds the minimum-cost path in weighted graphs without requiring a heuristic. The baseline optimal algorithm for weighted search.
Bidirectional Search
Searches simultaneously from start and goal, meeting in the middle. Reduces the effective branching factor exponentially, making it ideal for large unweighted graphs.
Architecture
src/search_library/
├── core/ # Base abstractions
│ ├── types.py # TypeVar T bound to Hashable
│ ├── nodes.py # Node dataclass (state, g_cost, h_cost, f_cost)
│ ├── problem.py # SearchProblem ABC (initial_state, is_goal, successors, heuristic)
│ └── result.py # SearchResult (path, total_cost, nodes_explored, success)
├── algorithms/ # Search implementations
│ ├── base.py # SearchAlgorithm ABC (unified interface)
│ ├── astar.py # A* Search
│ ├── bfs.py # Breadth-First Search
│ ├── dfs.py # Depth-First Search
│ ├── dijkstra.py # Dijkstra's Algorithm
│ └── bidirectional.py # Bidirectional BFS
├── heuristics/ # Pluggable heuristic functions
│ ├── base.py # Heuristic ABC (Strategy Pattern)
│ ├── manhattan.py # Manhattan distance (L1)
│ └── euclidean.py # Euclidean distance (L2)
├── graph/ # Weighted graph data structure
│ ├── graph.py # Graph + GraphSearchProblem adapter
│ └── edges.py # Edge dataclass
├── grid/ # 2D grid for pathfinding
│ ├── grid.py # Grid with obstacles, 4/8-directional movement
│ └── grid_search.py # GridSearchProblem adapter
├── utils/ # Visualization and formatting
└── exceptions/ # Custom error hierarchy
Design Principles
- SearchProblem defines the problem space (initial state, goal test, successors, heuristic)
- SearchAlgorithm is the unified interface all algorithms implement
- Adapter Pattern converts Graph/Grid into SearchProblem transparently
- Strategy Pattern makes heuristics interchangeable at runtime
- SOLID principles ensure each component has a single responsibility
Installation
pip install search-library
Or with uv:
uv add search-library
Usage
A* on a Weighted Graph
from search_library import Graph, AStarSearch
# Build a weighted undirected graph
graph = Graph[str](directed=False)
graph.add_edge("A", "B", 4.0)
graph.add_edge("B", "C", 2.0)
graph.add_edge("A", "C", 7.0)
graph.add_edge("C", "D", 1.0)
# Solve with A*
problem = graph.to_search_problem("A", "D")
result = AStarSearch(problem).search()
print(result.path) # ['A', 'B', 'C', 'D']
print(result.total_cost) # 7.0
print(result.nodes_explored) # 4
A* on a 2D Grid (Pathfinding)
from search_library import Grid, AStarSearch, ManhattanHeuristic
from search_library.grid import GridSearchProblem
# 0 = walkable, 1 = obstacle
maze = [
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 1, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 0, 0],
]
grid = Grid.from_matrix(maze)
problem = GridSearchProblem(grid, start=(0, 0), goal=(4, 4))
result = AStarSearch(problem).search()
print(result.success) # True
print(result.total_cost) # 8.0
print(result.steps) # 8
Comparing Algorithms
from search_library import Graph, AStarSearch, BFS, Dijkstra
graph = Graph[str](directed=False)
graph.add_edge("S", "A", 1.0)
graph.add_edge("S", "B", 4.0)
graph.add_edge("A", "B", 2.0)
graph.add_edge("B", "G", 1.0)
problem = graph.to_search_problem("S", "G")
for Algorithm in [AStarSearch, BFS, Dijkstra]:
result = Algorithm(problem).search()
print(f"{Algorithm.__name__:20} | cost={result.total_cost:.1f} | explored={result.nodes_explored}")
Convenience Functions
from search_library import astar_search, bfs_search, dfs_search, dijkstra_search
result = astar_search(problem)
result = bfs_search(problem, max_iterations=10000)
result = dijkstra_search(problem, strict=True)
result = dfs_search(problem, track_explored=True)
Grid Visualization
from search_library.utils import print_grid
grid = Grid.from_matrix(maze)
problem = GridSearchProblem(grid, (0, 0), (4, 4))
result = AStarSearch(problem).search(track_explored=True)
print_grid(grid, result, show_explored=True)
# S * * # .
# . # * # .
# . . * # .
# . # * * *
# . . . . G
Academic Use Cases
- Pathfinding: Optimal route computation in maps, games, and robotics
- Puzzle solving: N-puzzle, Rubik's cube via state-space search
- Knowledge graphs: Shortest path between concepts in semantic networks
- Algorithm comparison: Empirical analysis of search strategies (optimality, completeness, efficiency)
- AI education: Teaching informed vs. uninformed search with clean, readable code
- Research prototyping: Quick experimentation with custom search problems and heuristics
Complexity Analysis
| Algorithm | Time (worst) | Space (worst) | Optimal | Notes |
|---|---|---|---|---|
| A* | O(b^d) | O(b^d) | Yes* | *With admissible heuristic |
| BFS | O(V + E) | O(V) | Yes** | **For uniform-cost edges |
| DFS | O(V + E) | O(bm) | No | m = maximum depth |
| Dijkstra | O((V+E) log V) | O(V) | Yes | Non-negative weights required |
| Bidirectional | O(b^(d/2)) | O(b^(d/2)) | Yes** | **Unweighted / symmetric |
Development
# Clone and install
git clone https://github.com/ahincho/search-library.git
cd search-library
uv sync
# Run tests (147 tests, 96%+ coverage)
uv run pytest
# Lint and type-check
uv run ruff check src/ tests/
uv run mypy src/
# Build
uv build
Future Work
- Additional heuristics (Chebyshev, Octile, domain-specific)
- Iterative Deepening A* (IDA*)
- Weighted A* and anytime search
- Performance benchmarking suite
- Interactive visualization (matplotlib / terminal)
- Parallel search for large state spaces
References
- Hart, P. E., Nilsson, N. J., & Raphael, B. (1968). A Formal Basis for the Heuristic Determination of Minimum Cost Paths. IEEE Transactions on Systems Science and Cybernetics.
- Russell, S., & Norvig, P. (2020). Artificial Intelligence: A Modern Approach (4th ed.). Pearson.
- Cormen, T. H., et al. (2022). Introduction to Algorithms (4th ed.). MIT Press.
License
MIT — Free for academic and commercial use.
Author
Developed by ahincho at Universidad Nacional de San Agustin (UNSA).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file search_library-1.0.0.tar.gz.
File metadata
- Download URL: search_library-1.0.0.tar.gz
- Upload date:
- Size: 27.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4c9975a9b53e5ab6677e52a59b23bdf495ccf6d8b5c9042366af87cbc27d2b6
|
|
| MD5 |
e7b93335802b563fe6715c2ab5f6d6d2
|
|
| BLAKE2b-256 |
c5a103cca7eeb840dcb4d551fafefc83c84a8b27e34984e3da6e0f57fdd4e9c8
|
Provenance
The following attestation bundles were made for search_library-1.0.0.tar.gz:
Publisher:
cd.yml on ahincho/search-library
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
search_library-1.0.0.tar.gz -
Subject digest:
f4c9975a9b53e5ab6677e52a59b23bdf495ccf6d8b5c9042366af87cbc27d2b6 - Sigstore transparency entry: 1889380379
- Sigstore integration time:
-
Permalink:
ahincho/search-library@0809e782d508b191cf3f413b52565025071f207d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/ahincho
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
cd.yml@0809e782d508b191cf3f413b52565025071f207d -
Trigger Event:
push
-
Statement type:
File details
Details for the file search_library-1.0.0-py3-none-any.whl.
File metadata
- Download URL: search_library-1.0.0-py3-none-any.whl
- Upload date:
- Size: 31.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7074be27e6ec982e14cee8de69b4b948b451287c5276747ad79ea3ea83cb4e54
|
|
| MD5 |
36a6b78772852b766e4494bae7f3cec6
|
|
| BLAKE2b-256 |
bf338df70599b22e9b0d683b0ae5541786de79c193d4b88188bc32195468d5b8
|
Provenance
The following attestation bundles were made for search_library-1.0.0-py3-none-any.whl:
Publisher:
cd.yml on ahincho/search-library
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
search_library-1.0.0-py3-none-any.whl -
Subject digest:
7074be27e6ec982e14cee8de69b4b948b451287c5276747ad79ea3ea83cb4e54 - Sigstore transparency entry: 1889380476
- Sigstore integration time:
-
Permalink:
ahincho/search-library@0809e782d508b191cf3f413b52565025071f207d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/ahincho
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
cd.yml@0809e782d508b191cf3f413b52565025071f207d -
Trigger Event:
push
-
Statement type: