Practical Applications

Traveling Salesman Problem

The Traveling Salesman Problem (TSP) is a classic optimization problem in computer science and operations research. It involves finding the shortest possible route for a salesman to visit a set of cities exactly once and return to the starting point.

Example of code (with Informed (Heuristic) Search):

 
<?php

use app\classes\search\InformedSearchGraph;
use 
app\classes\search\UninformedSearchGraph;

// Function to run and analyze all search algorithms
function runSearch(InformedSearchGraph|UninformedSearchGraph $graphstring $startstring $goalstring $searchAlgorithm 'a-tree-search'string $algorithmDebug '') {
    
// Init algorithms
    
$searches = [];

    switch (
$searchAlgorithm) {
        
// Uninformed Search
        
case 'depth-first-search':
            
$searches['Depth First'] = fn () => $graph->dfs($start$goal);
            break;
        case 
'breadth-first-search':
            
$searches['Breadth First'] = fn () => $graph->bfs($start$goal);
            break;
        case 
'uniform-cost-search':
            
$searches['Uniform Cost Search'] = fn () => $graph->ucs($start$goalpathOnlytrue);
            break;
        case 
'iterative-deepening-depth-first':
            
$searches['Iterative Deepening Depth-First Search'] = fn () => $graph->iddfs($start$goalpathOnlytrue);
            break;
        case 
'bidirectional-first':
            
$searches['Bidirectional Search'] = fn () => $graph->bds($start$goalpathOnlytrue);
            break;
        case 
'depth-limited-search-2':
            
$searches['Depth-Limited Search (depth = 2)'] = fn () => $graph->dls($start2$goalpathOnlytrue);
            break;
        case 
'depth-limited-search-3':
            
$searches['Depth-Limited Search (depth = 3)'] = fn () => $graph->dls($start3$goalpathOnlytrue);
            break;
        case 
'random-walk-search':
            
$searches['Random Walk Search'] = fn () => $graph->rws($start$goalpathOnlytrue);
            break;

        
// Informed Search
        
case 'greedy-search':
            
$searches['Greedy Search'] = fn () => $graph->greedySearch($start$goal10);
            break;
        case 
'a-group-search':
            
$searches['A* Group Search'] = fn () => $graph->aStarGroupSearch($start$goal);
            break;
        case 
'beam-search-3':
            
$searches['Beam Search (width = 3)'] = fn () => $graph->beamSearch($start$goal3);
            break;
        case 
'beam-search-4':
            
$searches['Beam Search (width = 4)'] = fn () => $graph->beamSearch($start$goal4);
            break;
        case 
'ida-search':
            
$searches['IDA* Search'] = fn () => $graph->idaStarSearch($start$goal);
            break;
        case 
'simple-hill-climbing':
            
$searches['Simple Hill Climbing'] = fn () => $graph->simpleHillClimbing($start$goal);
            break;
        case 
'steepest-ascent-hill-climbing':
            
$searches['Steepest Ascent Hill Climbing'] = fn () => $graph->steepestAscentHillClimbing($start$goal);
            break;
        case 
'stochastic-hill-climbing':
            
$searches['Stochastic Hill Climbing'] = fn () => $graph->stochasticHillClimbing($start$goal);
            break;
        case 
'a-tree-search':
        default:
            
$searches['A* Tree Search'] = fn () => $graph->aStarTreeSearch($start$goal);
            break;
    }

    
$searchResult '';
    foreach (
$searches as $name => $searchFn) {
        echo 
"\n" str_repeat('-'50);
        echo 
"\n$name:\n";
        echo 
str_repeat('-'50) . "\n";

        try {
            
$startTime microtime(true);
            
$searchResult $searchFn();
            
$endTime microtime(true);

            if (
$algorithmDebug) {
                if (
$name === 'Greedy Search') {
                    
$searchResult $graph->debugGreedySearch($start$goal10);
                } elseif (
$name === 'A* Tree Search') {
                    
$searchResult $graph->debugAStarTreeSearch($start$goal);
                } elseif (
$name === 'A* Group Search') {
                    
$searchResult $graph->debugAStarGroupSearch($start$goal);
                } elseif (
$name === 'Beam Search (width = 3)') {
                    
$searchResult $graph->debugBeamSearch($start$goal3);
                } elseif (
$name === 'Beam Search (width = 4)') {
                    
$searchResult $graph->debugBeamSearch($start$goal4);
                } elseif (
$name === 'IDA* Search') {
                    
$searchResult $graph->debugIdaStarSearch($start$goal);
                } elseif (
$name === 'Simple Hill Climbing') {
                    
$searchResult $graph->debugSimpleHillClimbing($start$goal);
                } elseif (
$name === 'Steepest Ascent Hill Climbing') {
                    
$searchResult $graph->debugSteepestAscentHillClimbing($start$goal);
                } elseif (
$name === 'Stochastic Hill Climbing') {
                    
$searchResult $graph->debugStochasticHillClimbing($searchResult$start$goal);
                }
            }

            if (
$searchResult !== null) {
                
$graph->searchAnalysis($searchResult);
                
printf("Time taken: %.4f seconds\n"$endTime $startTime);
            } else {
                echo 
"No path found!\n";
            }
        } catch (
Exception $e) {
            echo 
'Error during search: ' $e->getMessage() . "\n";
        }
    }

    return 
$searchResult;
}

// Define start and goal cities
if ($searchAlgorithm === 'bidirectional-first') {
    
$startCity 'PHL';
    
$startCityName 'Philadelphia';
    
$goalCity 'SA';
    
$goalCityName 'San Antonio';
} else {
    
$startCity 'PHL';
    
$startCityName 'Philadelphia';
    
$goalCity 'HO';
    
$goalCityName 'Houston';
}

// Create graph and run searches
echo "Creating city graph and running all search algorithms...\n";
echo 
"Start: $startCityName, Goal: $goalCityName\n";

//echo "Distance calculations are in kilometers\n";
//$graph = createCityGraph($cities, $goalCity);

// Create the graph and add vertices with their levels
if (in_array($searchAlgorithm, ['depth-first-search''breadth-first-search''uniform-cost-search''iterative-deepening-depth-first''bidirectional-first''depth-limited-search-2''depth-limited-search-3''random-walk-search'])) {
    
$graph = new UninformedSearchGraph();
} else {

    
$graph = new InformedSearchGraph();
}

// Add all vertices with their heuristic values
// First parameter is vertex name, second is level (optional), third is heuristic value
$graph->addVertex('PHL'03843.5'Philadelphia');
$graph->addVertex('MI'23758.8'Miami');
$graph->addVertex('NY'13835.7'New York');
$graph->addVertex('CH'22804.0'Chicago');
$graph->addVertex('LA'21234.3'Los Angeles');
$graph->addVertex('DA'31992.0'Dallas');
$graph->addVertex('HO'32206.3'Houston');
$graph->addVertex('PH'3574.3'Phoenix');
$graph->addVertex('SD'3179.4'San Diego');
$graph->addVertex('SA'41933.8'San Antonio');

// Add all edges with their costs
$graph->addEdge('LA''PH'574.3);
$graph->addEdge('LA''SD'179.4);
$graph->addEdge('LA''NY'3935.7);

$graph->addEdge('PH''LA'574.3);
$graph->addEdge('PH''SD'480.9);

$graph->addEdge('SD''PH'480.9);
$graph->addEdge('SD''LA'179.4);

$graph->addEdge('CH''DA'1294.9);
$graph->addEdge('CH''NY'1144.3);

$graph->addEdge('DA''CH'1294.9);
$graph->addEdge('DA''SA'406.3);
$graph->addEdge('DA''HO'361.8);

$graph->addEdge('SA''DA'406.3);
$graph->addEdge('SA''HO'304.3);

$graph->addEdge('HO''SA'304.3);
$graph->addEdge('HO''DA'361.8);
$graph->addEdge('HO''MI'1556.8);

$graph->addEdge('MI''HO'1556.8);
$graph->addEdge('MI''NY'1757.9);

$graph->addEdge('NY''MI'1757.9);
$graph->addEdge('NY''PHL'129.6);
$graph->addEdge('NY''CH'1144.3);
$graph->addEdge('NY''LA'3935.7);

$graph->addEdge('PHL''NY'129.6);

$searchResult runSearch($graph$startCity$goalCity$searchAlgorithm$algorithmDebug);