views:

354

answers:

4

Hello, I have this function that I wrote that is abysmally slow since php does not handle recursion well. I am trying to convert it to a while loop, but am having trouble wrapping my head around how to do it.

Can anyone give me some tips?

    public function findRoute($curLoc, $distanceSoFar, $expectedValue) {

    $this->locationsVisited[$curLoc] = true;
    $expectedValue += $this->locationsArray[$curLoc]*$distanceSoFar;

    $at_end = true;
    for($i = 1; $i < $this->numLocations; $i++) {
        if($this->locationsVisited[$i] == false) {
            $at_end = false;

            if($expectedValue < $this->bestEV)
                $this->findRoute($i, $distanceSoFar + $this->distanceArray[$curLoc][$i], $expectedValue);
        }
    }

    $this->locationsVisited[$curLoc] = false;

    if($at_end) {
        if($expectedValue < $this->bestEV) {
            $this->bestEV = $expectedValue;
        }
    }
}
+2  A: 

You can convert a recursive function into an iterative function by using a stack to store the current state. Look into array_push() and array_pop().

Ignacio Vazquez-Abrams
+5  A: 

I'm not going to convert your code, but you can convert a recusive function into an iterative one by creating a stack:

$stack= array();

And instead of invoking $this->findroute(), push your parameters onto this stack:

$stack[] = array($i, $distanceSoFar + $this->distanceArray[$curLoc][$i], $expectedValue);

Now surround basically everything in your function into a while loop draining the stack after having primed it:

while (count($stack)) { 
    // Do stuff you already do in your function here
Kristopher Ives
This has given me a good start but I'm having trouble figuring out what to do with the backtracking step. I need to set $this->locationsVisited[$curLoc] = true then iterate with it true and then turn it off again.
Eric
A: 

At a glance I don't think recursion is your problem, yes it's slow in PHP, but It looks like your going over values more than you need to, putting the values in a stack, or several stacks and handling them, may be nice.

custom sort functions have always helped me with problems of this sort.

function sort_by_visited($x,$y)
{
   return ($this->locationsVisited[$x] > $this->locationsVisited[$y]) ? -1 : 1;
}

uasort($locationsVisited,'sort_by_visited');

This will prioritize all not visited locations at the top of the stack.

Fire Crow
A: 

This looks like your trying to find the optimal route for traversal of a series of nodes in a graph.

I'm guessing that you've not studied Computer Science as the "Travelling Salesman" problem is an archetype of Artificial Intelligence. Of course, as such, it has its own Wikipedia page:

http://en.wikipedia.org/wiki/Travelling%5Fsalesman%5Fproblem

Sorry - but just swapping from a recursive to an iterative function isn't going to make it go any faster ("php does not handle recursion well." - can you provide reference for this assertion). If you need a faster solution then you'll need to look at non-exhaustive/fuzzy methods.

C.

symcbean
"[7 Aug 1999 12:25pm UTC] zeev at cvs dot php dot netPHP 4.0 (Zend) uses the stack for intensive data, rather than usingthe heap. That means that its tolerance recursive functionsis significantly lower than that of other languages.It's relatively easy to tell Zend not to use the stack for thisdata, and use the heap instead - which would greatly increase thenumber of recursive functions possible - in the price of reducedspeed. If you're interested in such a setting, let me know, wemay add a compile-time switch."I should probably just switch to C or something..
Eric
It says "tolerance" nothing about performance or reliablitiy - I think you'll find that the implication of this statement is the recursion is therefore limited by the stack size (which by default is much smaller than the heap in most setups.Switching your development to C isn't going to reduce the order of the algorithm - it'll still be N!C.
symcbean