pathfinding-indexed 4.15.0

Index-only pathfinding, flow, and graph algorithms
Documentation
# Working with Indexed Graphs in pathfinding-indexed

This guide explains how to use `pathfinding-indexed` with traditional graph structures consisting of
nodes, edges, and weights. The library is index-only: nodes are dense `usize` indices, and the
algorithms are methods on indexed graph types.

## Core Concept: Dense Indices

Every node is represented by an index in `0..node_count`. You can build graphs directly from
adjacency lists or undirected edge lists, or use a mapping helper to assign indices to external
node values.

## Directed Graphs: Adjacency List

An adjacency list stores each node's outgoing neighbors and edge weights. This is efficient for
sparse graphs.

```rust
use pathfinding_indexed::IndexedGraph;

let graph = IndexedGraph::from_adjacency(vec![
    vec![(1, 4), (2, 2)],
    vec![(2, 1), (3, 5)],
    vec![(3, 8), (4, 10)],
    vec![(4, 2)],
    vec![],
]);

let result = graph.dijkstra(0, |node| node == 4);
assert_eq!(result, Some((vec![0, 1, 2, 3, 4], 12)));
```

## Directed Graphs: Adjacency Matrix

For dense graphs you might start from an adjacency matrix. Convert it to an adjacency list before
building the graph.

```rust
use pathfinding_indexed::IndexedGraph;

let matrix: Vec<Vec<Option<u32>>> = vec![
    vec![None, Some(4), Some(2), None, None],
    vec![None, None, Some(1), Some(5), None],
    vec![None, None, None, Some(8), Some(10)],
    vec![None, None, None, None, Some(2)],
    vec![None, None, None, None, None],
];

let adjacency = matrix
    .iter()
    .enumerate()
    .map(|(i, row)| {
        row.iter()
            .enumerate()
            .filter_map(|(j, weight)| weight.map(|w| (j, w)))
            .collect::<Vec<_>>()
    })
    .collect::<Vec<_>>();

let graph = IndexedGraph::from_adjacency(adjacency);
let result = graph.dijkstra(0, |node| node == 4);
assert_eq!(result, Some((vec![0, 2, 3, 4], 12)));
```

If you already have an adjacency matrix, you can skip the manual conversion:

```rust
use pathfinding_indexed::IndexedGraph;

let graph = IndexedGraph::from_adjacency_matrix(&[
    vec![None, Some(4), Some(2), None],
    vec![None, None, Some(1), Some(5)],
    vec![None, None, None, Some(8)],
    vec![None, None, None, None],
])
.unwrap();

let result = graph.dijkstra(0, |node| node == 3);
assert_eq!(result, Some((vec![0, 1, 3], 9)));
```

## Undirected Graphs: Edge List

Undirected graphs store each edge once and expose symmetric adjacency lists.

```rust
use pathfinding_indexed::IndexedUndirectedGraph;

let edges = vec![
    (0, 1, 4),
    (0, 2, 2),
    (1, 2, 1),
    (1, 3, 5),
    (2, 3, 8),
];

let graph = IndexedUndirectedGraph::from_edges(4, edges);
let mst = graph.kruskal();
assert_eq!(mst.len(), 3);
```

## Mapping External Node Values

If your nodes are not indices, use the mapping helper to assign dense indices and build an indexed
graph without affecting algorithm hot paths.

```rust
use pathfinding_indexed::IndexedGraphMap;
use std::collections::HashMap;

let raw: HashMap<&str, Vec<(&str, u32)>> = [
    ("A", vec![("B", 4), ("C", 2)]),
    ("B", vec![("C", 1), ("D", 5)]),
    ("C", vec![("D", 8), ("E", 10)]),
    ("D", vec![("E", 2)]),
    ("E", vec![]),
]
.into_iter()
.collect();

let mapped = IndexedGraphMap::from_nodes_and_successors(["A"], |node| {
    raw.get(node).cloned().unwrap_or_default()
});

let start = mapped.index_of(&"A").unwrap();
let goal = mapped.index_of(&"E").unwrap();

let result = mapped.graph().dijkstra(start, |node| node == goal);
let (path, cost) = result.expect(\"no path found\");
assert_eq!(*path.first().unwrap(), start);
assert_eq!(*path.last().unwrap(), goal);
assert_eq!(cost, 6);
```

## Walkable Grid Inputs

For blocked/unblocked map data, use the walkable-matrix helpers to build a graph map whose external
node labels are `(row, column)` coordinates.

```rust
use pathfinding_indexed::IndexedGraphMap;

let mapped = IndexedGraphMap::from_walkable_matrix_4(&[
    vec![true, true, false],
    vec![false, true, true],
])
.unwrap();

let start = mapped.index_of(&(0, 0)).unwrap();
let goal = mapped.index_of(&(1, 2)).unwrap();
let result = mapped.graph().dijkstra(start, |node| node == goal);
assert_eq!(result.map(|(_, cost)| cost), Some(3));
```

If your data already lives in another grid container, use the predicate-based helpers:

```rust
use pathfinding_indexed::IndexedGraphMap;

let mapped = IndexedGraphMap::from_walkable_cells_8(3, 3, |cell| {
    !matches!(cell, (1, 1))
});

assert!(mapped.index_of(&(0, 0)).is_some());
assert!(mapped.index_of(&(1, 1)).is_none());
```