@@ -144,139 +144,35 @@ class DStarLite(
144144 }
145145
146146 /* *
147- * Invalidates a node (e.g., it became an obstacle) and updates affected neighbors.
147+ * Invalidates a node and updates affected neighbors.
148148 * Also updates the neighbors of neighbors to ensure diagonal paths are correctly recalculated.
149149 * Optionally prunes the graph after invalidation to remove unnecessary nodes and edges.
150150 *
151151 * @param u The node to invalidate
152- * @param pruneGraph Whether to prune the graph after invalidation
153152 */
154- fun invalidate (u : FastVector , pruneGraph : Boolean = true) {
155- val newNodes = mutableSetOf<FastVector >()
156- val affectedNeighbors = mutableSetOf<FastVector >()
157- val pathNodes = mutableSetOf<FastVector >()
158- val modifiedNodes = mutableSetOf<FastVector >()
159-
160- // Add the invalidated node to the modified nodes
161- modifiedNodes.add(u)
162-
163- // First, collect all neighbors of the invalidated node
164- val neighbors = graph.neighbors(u)
165- affectedNeighbors.addAll(neighbors)
166- modifiedNodes.addAll(neighbors)
167-
168- // Set g and rhs values of the invalidated node to infinity
169- setG(u, INF )
170- setRHS(u, INF )
171- updateVertex(u)
172-
173- // Update edges between the invalidated node and its neighbors
174- neighbors.forEach { v ->
175- val current = graph.successors(v)
153+ fun invalidate (u : FastVector , prune : Boolean = false) {
154+ val modified = mutableSetOf (u)
155+ (graph.neighbors(u) + u).forEach { v ->
156+ val current = graph.neighbors(v)
176157 val updated = graph.nodeInitializer(v)
177- val removed = current.filter { (w, _) -> w !in updated }
178-
179- // Only add new nodes that are directly connected to the current path
180- // This reduces unnecessary node generation
181- updated.keys.filter { w -> w !in current.keys && w != u }.forEach {
182- // Check if this node is likely to be on a new path
183- if (g(v) < INF ) {
184- newNodes.add(it)
185- modifiedNodes.add(it)
186- }
187- }
188-
189- // Set the edge cost between u and v to infinity (blocked)
190- updateEdge(u, v, INF )
191- updateEdge(v, u, INF )
192-
193- // Update removed and new edges for this neighbor
194- removed.forEach { (w, _) ->
158+ val removed = current.filter { w -> w !in updated }
159+ removed.forEach { w ->
195160 updateEdge(v, w, INF )
196161 updateEdge(w, v, INF )
197- modifiedNodes.add(w)
198162 }
199163 updated.forEach { (w, c) ->
200164 updateEdge(v, w, c)
201165 updateEdge(w, v, c)
202- modifiedNodes.add(w)
203- }
204- }
205-
206- // Now, update only the neighbors of neighbors that are likely to be on the new path
207- // This is crucial when a node in a diagonal path is blocked
208- neighbors.forEach { v ->
209- // Only process neighbors that are likely to be on the path
210- if (g(v) >= INF ) return @forEach
211- pathNodes.add(v)
212-
213- // Get all neighbors of this neighbor (excluding the original invalidated node)
214- // Only consider neighbors that are likely to be on the path
215- val secondaryNeighbors = graph.neighbors(v).filter { it != u && g(it) < INF }
216-
217- // For each secondary neighbor, reinitialize its edges
218- secondaryNeighbors.forEach { w ->
219- // Add to affected neighbors for later rhs update
220- affectedNeighbors.add(w)
221- pathNodes.add(w)
222- modifiedNodes.add(w)
223-
224- // Reinitialize edges for this secondary neighbor
225- val currentW = graph.successors(w)
226- val updatedW = graph.nodeInitializer(w)
227-
228- // Update edges for this secondary neighbor
229- // Only update edges to nodes that are likely to be on the path
230- updatedW.forEach { (z, c) ->
231- if (z != u) { // Don't create edges to the invalidated node
232- updateEdge(w, z, c)
233- updateEdge(z, w, c)
234- modifiedNodes.add(z)
235-
236- // If this node has a finite g-value, it's likely on the path
237- if (g(z) < INF ) {
238- pathNodes.add(z)
239- }
240- }
241- }
242-
243- // Add any new nodes discovered, but only if they're likely to be on the path
244- updatedW.keys.filter { z -> z !in currentW.keys && z != u }.forEach {
245- // Check if this node is connected to a node on the path
246- if (g(w) < INF ) {
247- newNodes.add(it)
248- modifiedNodes.add(it)
249- }
250- }
251- }
252- }
253-
254- // Ensure all edges to/from the invalidated node are set to infinity
255- // First, get all current successors and predecessors of the invalidated node
256- val currentSuccessors = graph.successors(u).keys.toSet()
257- val currentPredecessors = graph.predecessors(u).keys.toSet()
258-
259- // Set all edges to/from the invalidated node to infinity
260- (currentSuccessors + currentPredecessors + graph.nodes).forEach { node ->
261- if (node != u) {
262- updateEdge(node, u, INF )
263- updateEdge(u, node, INF )
264- modifiedNodes.add(node)
265- }
266- }
267-
268- // Update rhs values for all affected nodes
269- (affectedNeighbors + newNodes).forEach { node ->
270- if (node != goal) {
271- setRHS(node, minSuccessorCost(node))
272- updateVertex(node)
273166 }
167+ modified.addAll(removed + updated.keys + v)
274168 }
169+ if (prune) prune(modified)
170+ }
275171
276- // Prune the graph if requested
277- if (pruneGraph) {
278- // Prune the graph, passing the modified nodes for targeted pruning
279- graph.prune(modifiedNodes )
172+ private fun prune ( modifiedNodes : Set < FastVector > = emptySet()) {
173+ graph.prune(modifiedNodes).forEach {
174+ gMap.remove(it)
175+ rhsMap.remove(it )
280176 }
281177 }
282178
@@ -289,14 +185,21 @@ class DStarLite(
289185 */
290186 fun updateEdge (u : FastVector , v : FastVector , c : Double ) {
291187 val cOld = graph.cost(u, v)
292- if (cOld == c) return
293188 graph.setCost(u, v, c)
189+ // LOG.info("Setting edge ${u.string} -> ${v.string} to $c")
294190 if (cOld > c) {
295- if (u != goal) setRHS(u, min(rhs(u), c + g(v)))
191+ if (u != goal) {
192+ setRHS(u, min(rhs(u), c + g(v)))
193+ // LOG.info("Setting RHS of ${u.string} to ${rhs(u)}")
194+ }
296195 } else if (rhs(u) == cOld + g(v)) {
297- if (u != goal) setRHS(u, minSuccessorCost(u))
196+ if (u != goal) {
197+ setRHS(u, minSuccessorCost(u))
198+ // LOG.info("Setting RHS of ${u.string} to ${rhs(u)}")
199+ }
298200 }
299201 updateVertex(u)
202+ // LOG.info("Updated vertex ${u.string}")
300203 }
301204
302205 /* *
@@ -309,38 +212,19 @@ class DStarLite(
309212 */
310213 fun path (maxLength : Int = 10_000): List <FastVector > {
311214 val path = mutableListOf<FastVector >()
312- if (start !in graph) return path.toList() // Start not even known
215+ if (start !in graph) return emptyList()
216+ if (rhs(start) == INF ) return emptyList()
313217
314218 var current = start
315219 path.add(current)
316220
317221 var iterations = 0
318222 while (current != goal && iterations < maxLength) {
319223 iterations++
320- val successors = graph.successors(current)
321- if (successors.isEmpty()) break // Dead end
322-
323- var bestNext: FastVector ? = null
324- var minCost = INF
325-
326- // Find successor s' that minimizes c(current, s') + g(s')
327- for ((succ, cost) in successors) {
328- if (cost == INF ) continue // Skip impassable edges explicitly
329- val costPlusG = cost + g(succ)
330- if (costPlusG < minCost) {
331- minCost = costPlusG
332- bestNext = succ
333- }
334- }
335-
336- if (bestNext == null ) break // No path found
337-
338- current = bestNext
339- if (current !in path) { // Avoid trivial cycles
340- path.add(current)
341- } else {
342- break // Cycle detected
343- }
224+ val cheapest = graph.successors(current)
225+ .minByOrNull { (succ, cost) -> cost + g(succ) } ? : break
226+ current = cheapest.key
227+ if (current !in path) path.add(current) else break
344228 }
345229 return path
346230 }
0 commit comments