1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
//! Common functional utilities for tree traversal algorithms.
use ;
use crateScoredItem;
/// Performs a generic traversal over a tree iterator, collecting the best leaf nodes based on their costs.
///
/// This function iterates through the provided tree, checks each node to determine if it's a leaf using the `leaf_check_fn`,
/// computes its cost using the `cost_fn`, and maintains a priority queue of the top `queue_size` nodes with the lowest costs.
/// The traversal stops early if the maximum number of operations (`max_ops`) is reached or the time limit is exceeded.
///
/// The `callback_fn` is invoked for every visited node with its index and a reference to the node. It can be used for
/// progress reporting, logging, or other side-effects. The callback is called before leaf/cost checks.
///
/// # Parameters
/// - `tree`: A mutable reference to a fused iterator over the tree nodes.
/// - `leaf_check_fn`: A function that checks if a node is a leaf.
/// - `cost_fn`: A function that computes the cost of a node, returning `None` if the cost cannot be determined.
/// - `max_ops`: The maximum number of nodes to process.
/// - `time_limit`: The maximum time allowed for the traversal.
/// - `queue_size`: The maximum number of best nodes to keep in the result.
/// - `callback_fn`: A mutable callback invoked as `callback_fn(n_step, &node)` for each visited node.
///
/// # Returns
/// A vector of tuples containing the cost and the node, limited to `queue_size`.
/// Finds the best (lowest cost) leaf node in the tree iterator within the given constraints.
///
/// This function is a convenience wrapper around `traverse` that returns only the single best node.
/// It accepts the same parameters as `traverse`, including `callback_fn`, which is invoked for each
/// visited node. Use the callback for logging, progress updates, or to collect statistics about visited nodes.
///
/// # Parameters
/// - `tree`: A mutable reference to a fused iterator over the tree nodes.
/// - `leaf_check_fn`: A function that checks if a node is a leaf.
/// - `cost_fn`: A function that computes the cost of a node, returning `None` if the cost cannot be determined.
/// - `max_ops`: The maximum number of nodes to process.
/// - `time_limit`: The maximum time allowed for the traversal.
/// - `callback_fn`: A mutable callback invoked as `callback_fn(n_step, &node)` for each visited node.
///
/// # Returns
/// The best (lowest cost) leaf node and its cost, or `None` if no valid leaf is found.
/// A trait representing a container that holds the frontier of nodes during a traversal.
///
/// This trait is the core abstraction used by traversal drivers such as [`Reachable`].
/// It decouples *how* nodes are stored and scheduled for visiting (stack, queue, priority
/// queue, etc.) from the traversal logic itself.
///
/// # Traversal contract
///
/// A typical traversal loop using a `NodeContainer` behaves as follows:
///
/// 1. Repeatedly call [`pop`](NodeContainer::pop) to obtain the next node to visit.
/// 2. For each node returned as `Some(node)`, call
/// [`expand_and_push`](NodeContainer::expand_and_push) with a reference to that node.
/// This method is responsible for discovering the node's children and inserting them
/// into the container.
/// 3. When [`pop`](NodeContainer::pop) returns `None`, the container is empty and the
/// traversal is finished.
///
/// The [`Reachable`] iterator follows exactly this protocol in its [`Iterator::next`]
/// implementation: it calls `pop()`, then (if successful) immediately calls
/// `expand_and_push(&node)` with the popped node.
///
/// # Traversal order
///
/// The concrete `NodeContainer` implementation fully determines the traversal order:
///
/// - A stack-like container (LIFO) results in a depth-first traversal.
/// - A queue-like container (FIFO) results in a breadth-first traversal.
/// - A priority-based container can implement best-first, Dijkstra-like, or A*-like
/// traversals, depending on the priority policy.
///
/// Implementations are expected to store nodes (and any associated metadata they need)
/// internally and to be safe for repeated `pop` / `expand_and_push` cycles as described
/// above.
/// An iterator that traverses a tree or graph by yielding nodes reachable from a starting point.
///
/// This struct implements the standard [`Iterator`] trait, producing nodes in an order determined
/// by the underlying [`NodeContainer`]. It encapsulates the traversal logic, repeatedly calling
/// [`NodeContainer::pop`] to obtain the next node and [`NodeContainer::expand_and_push`] to
/// expand it, following the traversal contract defined by [`NodeContainer`].
///
/// The traversal order depends on the [`NodeContainer`] implementation:
/// - Stack-based containers (e.g., depth-first) yield nodes in LIFO order.
/// - Queue-based containers (e.g., breadth-first) yield nodes in FIFO order.
/// - Priority-based containers yield nodes based on a priority function.
///
/// The [`NodeContainer`] trait abstracts the data structure used to manage the frontier of nodes
/// to be visited, decoupling the traversal strategy from the iteration logic. This allows
/// `Reachable` to work with various traversal algorithms by simply swapping the container type.
///
/// # Type Parameters
/// - `C`: The type of the node container, which must implement [`NodeContainer`].
///
/// # Examples
/// See the documentation of specific traversal functions like [`bfs_reach`] or [`dfs_reach`]
/// for usage examples.