Skip to main content

PATHOS — Python AI Search Library

CI PyPI Python License: MIT

Production-ready classical AI search algorithms for Python. No machine learning. Pure search.

Documentation · PyPI · Examples

Philosophy

Define your problem, not your algorithm. PATHOS inspects the capabilities you declare and selects the best algorithm automatically.

from pathos import Space

space = Space().initial("Madrid")

@space.successors
def neighbors(city):
    for next_city, km in roads[city]:
        yield next_city, next_city

@space.goal
def reached(city): return city == "Lisboa"

@space.heuristic
def h(city): return straight_line_km(city, "Lisboa")

result = space.solver().solve()
# → Uses A* automatically (has successors + goal + heuristic)
print(result.path, result.cost, result.algorithm)

Install

pip install pathos-ai

Algorithm Families

Declare Algorithms Available
@evaluate Simulated Annealing, Genetic Algorithm, DE, PSO
@successors + @goal BFS, DFS, IDDFS (DFS is non-optimal — for shortest paths prefer BFS/UCS)
@successors + @evaluate Hill Climbing, Tabu Search, Simulated Annealing — cascaded by AnytimeLocal under mode="auto"
@successors + @goal + @heuristic A*, IDA*, Greedy Best-First
@successors + @goal + @heuristic + @evaluate Weighted A*, UCS
.adversarial() + @terminal + @utility Minimax, Alpha-Beta, Negamax, MCTS — iterative-deepened by AnytimeAdversarial under mode="auto" with PV-first move ordering
CSPSpace + @constraint Backtracking, Forward Checking, Min-Conflicts (with @evaluate) — cascaded by AnytimeCSP under mode="auto"

Specialized Spaces

from pathos import GraphSpace, CSPSpace, TourSpace, GameSpace

# Graph search (auto-provides successors from adjacency)
space = GraphSpace(graph=city_graph).initial("A")

# Constraint satisfaction (auto-provides successors + goal)
csp = CSPSpace(variables=["X", "Y", "Z"])

# Tour optimization (TSP — auto-provides 2-opt neighborhood)
tour = TourSpace(nodes=cities, distances=dist_matrix)

# Adversarial games (auto-sets adversarial mode)
game = GameSpace().initial(board)

Modes — exact, approximate, auto

The solver() factory selects an algorithm based on the space's declared capabilities and the mode you ask for. Three modes:

# Default: anytime cascade. Always-ready, gives best incumbent under
# the budget (1h if you don't set one). Optimal if it finishes.
space.solver().solve()
space.solver(timeout=60).solve()

# Single-shot admissible algorithm. No timeout default; runs to
# completion or until you cut it off.
space.solver(mode="exact").solve()

# Single-shot bounded-suboptimal algorithm. Faster than exact.
space.solver(mode="approximate").solve()

Under mode="auto" (default), AnytimeAStar wins selection on A*-family spaces and runs a cascade [Greedy, WAStar(5,3,2,1.5), AStar], keeping the best incumbent across phases. On a generous budget the final A* phase returns the proven-optimal answer; on a tight budget you get the best incumbent so far instead of not_found.

On CSP-shaped spaces (CSPSpace or any space whose initial state is a partial-assignment dict), AnytimeCSP wins selection under mode="auto" and runs a cascade [MinConflicts, Backtracking] — MinConflicts is only included when @evaluate is declared (it greedily picks the lowest- violation child). The first phase that returns a consistent complete assignment wins; if MinConflicts gives up, Backtracking takes over.

On pure-optimization spaces (@successors + @evaluate, no @goal), AnytimeLocal wins selection under mode="auto" and runs a cascade [HillClimbing, SimulatedAnnealing, TabuSearch] — a fast-probe followed by two escape phases. The best (lowest-cost) incumbent across all phases is returned; cancellation mid-cascade keeps whichever incumbent was already planted. AnytimeLocal does not declare @goal, so on goal-bearing spaces the selector keeps AnytimeAStar (with @heuristic) or the uninformed goal algorithms in charge.

On adversarial spaces (.adversarial() + @terminal + @utility), AnytimeAdversarial wins selection under mode="auto" and iteratively deepens from depth 1 to max_depth over AlphaBeta (2-player) or Negamax (3+ player), threading the previous depth's principal variation as pv_hint into the next phase for move ordering — α-β pruning becomes substantially more effective with a good first move. Cancellation mid-deepening keeps the best move from the deepest completed depth.

SearchResult.epsilon tells you the quality bound: 1.0 is proven optimal, >1.0 is ε-bounded (cost ≤ ε × optimal), inf is unbounded (greedy), None means the algorithm doesn't report a bound (e.g. metaheuristics).

result = space.solver(timeout=10).solve()
if result.optimal:
    print(f"Optimal: cost {result.cost}")
else:
    print(f"ε-bounded ({result.epsilon}): cost {result.cost}")

Every metaheuristic is naturally anytime regardless of mode — set a timeout and the algorithm returns its best individual seen so far when the budget runs out (cooperative CancelToken protocol).

Parallel Evaluation

Population-based algorithms (GA, DE, LocalBeamSearch) support multiprocessing via .parallel(n):

# Evaluate all candidates in parallel across 4 processes
space = Space().initial(lambda: random_genome()).parallel(4)

# evaluate fn must be a module-level function (picklable)
def fitness(genome): return -sum(genome)
space.evaluate(fitness)

result = GeneticAlgorithm(space, pop_size=200, generations=500).solve()

Pass n=1 (default) for serial execution. Falls back automatically when population size is 1.

Direct Algorithm Access

from pathos.algorithms import AStar, GeneticAlgorithm, AlphaBeta

result = AStar(space).solve()  # bypass auto-selection

SearchResult

Every algorithm returns a uniform SearchResult:

result.solution      # final state
result.path          # list of (action, state) steps
result.cost          # total cost
result.algorithm     # algorithm name
result.nodes_expanded
result.elapsed       # seconds
result.found         # bool

Performance

Reference numbers from python -m benchmarks.bench --repeat 3 on an Intel i7-6820HQ @ 2.70 GHz, Python 3.13. Algorithms are the ones auto-selected by space.solver(). Reproduce with the same command; raw records dumped via --json.

N-Queens (Backtracking, CSPSpace)

N elapsed (s, median) nodes expanded
6 0.0003 31
8 0.0022 113
10 0.0031 102
12 0.0149 261
14 0.1726 1 899
16 1.2363 10 052

TSP (TabuSearch, TourSpace, 100 iters)

cities elapsed (s, median) tour cost (median)
5 0.0014 197.8
8 0.0060 253.3
12 0.0224 272.2
16 0.0439 354.9
20 0.0800 383.4
25 0.1593 409.3

8-Puzzle (A* + Manhattan)

scramble depth elapsed (s, median) nodes expanded solution length
10 0.0001 12 10
20 0.0042 461 20
30 0.0097 1 397 24
40 0.0127 1 728 26
50 0.0086 1 186 22

Solution length plateaus around 22–26 because the 8-puzzle state-space diameter is ~31 — deeper scrambles don't make harder instances.

Examples

License

MIT — gia-uh

Metadata

Release files for pathos-ai 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pathos-ai 0.2.0
File Size Uploaded
pathos_ai-0.2.0.tar.gz 97.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pathos-ai 0.2.0
File Interpreter ABI Platform
pathos_ai-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 134.5 kB

Release files / pathos_ai-0.2.0.tar.gz

Download URL pathos_ai-0.2.0.tar.gz
Size 97.4 kB
Tags Source
SHA-256 checksum
How to use checksums
3ea338341b45db2d066a41f00fde4306769ca6d9ad625d204bbc4fa053d0cb25
BLAKE2b-256 checksum
How to use checksums
0b751dba4ebef033b235a75e8ba09fa935acf1c27f59f09218633f559ca3c993
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 3, 2026.

Transparency log

Release files / pathos_ai-0.2.0-py3-none-any.whl

Download URL pathos_ai-0.2.0-py3-none-any.whl
Size 37.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1cfb6c35ca0ba6a488c1498034b1481f0cbbf582787eec4a36c327558c1a47e7
BLAKE2b-256 checksum
How to use checksums
203464b63182044cee85b00cc78ef429a0febe7e02760137acb8ec0929b8234b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page