evenfurther / pathfinding

Pathfinding library for rust

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Thoughts on removing `successors` allocation

chinedufn opened this issue · comments

Hey!

I'm exploring using pathfinding's astar implementation.

I'm noticing that the successors function requires you to allocate a vector.

This is probably fine for most use cases - but if you're targeting a top-performance pathfinding implementation it might be a non-starter.

Has removing this allocation been considered?


The signature for successors is currently:

fn successors(&self) -> Vec<(Pos, usize)> {

Have it been considered to instead have fn successors(&self) -> &Vec<(Pos, usize)> { be the signature?

Then the documentation could just show an example of using a re-usable Vec<T, usize>. The ergonomics would be roughly identical minus the user needing to clear the vector out or something like that...

i.e. (rough sketch)

let mut successors = vec![];

astar(
        start,
        |p| {
            successors.clear();
            p.successors(&successors)
        }
        |p| p.chebyshev_distance(end),
        |p| p == end,
);

Thoughts?

Thanks!

It looks like there are a few other allocations within the astar implementation - just curious about the willingness or lack thereof to expose a way to avoid some of the ones that aren't necessary?

I haven't benchmarked my application (lots and lots of pathfinding) yet to see the difference in performance - so I'm mainly just throwing out an early question to get a sense of what has already been explored here vs. what has not.

Thanks!

The signature for successors in astar() is

  successors: FN
  where
      FN: FnMut(&N) -> IN,
      IN: IntoIterator<Item = (N, C)>,

This does not force you to allocate a vector. In fact, you could even implement IntoIterator for a usize-sized structure which would unsafely return the copy of an element in a vector that you reuse for every call to successors. I modified an example and a test in commit e64b732 to make this clearer.

Concerning the other allocations, they are necessary in order to implement the A* algorithm. If you find more efficient implementations, I would gladly accept pull requests.

Ah silly me just reading the examples instead of car fully examining the functions! Thank you.

Hmmm maybe I’m missing something - but the BinaryHeap::new() call at the beginning of astar appears to be allocating - and to me it appears possible to provide that underlying Vec instead of creating it every time.

But my main issue was around successors - which you’ve helped me with already. I don’t plan to do any benchmarking for months but if I have any real hard numbers in the future I’ll come back to ya!

Thanks!