Home > matGeom > graphs > grShortestPath.m

grShortestPath

PURPOSE ^

GRSHORTESTPATH Find a shortest path between two nodes in the graph.

SYNOPSIS ^

function [nodePath, edgePath] = grShortestPath(nodes, edges, ind0, ind1, edgeWeights)

DESCRIPTION ^

GRSHORTESTPATH Find a shortest path between two nodes in the graph.

   PATH = grShortestPath(NODES, EDGES, NODE1, NODE2, WEIGHTS)
   NODES and EDGES defines the graph, NODE1 and NODE2 are indices of the
   node extremities, and WEIGHTS is the set of weights associated to each
   edge.
   The function returns a set of node indices.

   PATH = grShortestPath(NODES, EDGES, NODEINDS, WEIGHTS)
   Specifies two or more points that must be traversed by the path, in the
   specified order.

   % Create a simple tree graph, and compute shortest path
     [x y] = meshgrid([10 20 30], [10 20 30]);
     nodes = [x(:) y(:)];
     edges = [1 2;2 3;2 5;3 6; 4 5;4 7;5 8; 8 9];
     drawGraph(nodes, edges)
     axis equal; axis([0 40 0 40]);
     drawNodeLabels(nodes, 1:9)
     path = grShortestPath(nodes, edges, 1, 9);
     % same as:
     path = grShortestPath(nodes, edges, [1 9]);

   See also
     graphs, grFindMaximalLengthPath

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function [nodePath, edgePath] = grShortestPath(nodes, edges, ind0, ind1, edgeWeights)
0002 %GRSHORTESTPATH Find a shortest path between two nodes in the graph.
0003 %
0004 %   PATH = grShortestPath(NODES, EDGES, NODE1, NODE2, WEIGHTS)
0005 %   NODES and EDGES defines the graph, NODE1 and NODE2 are indices of the
0006 %   node extremities, and WEIGHTS is the set of weights associated to each
0007 %   edge.
0008 %   The function returns a set of node indices.
0009 %
0010 %   PATH = grShortestPath(NODES, EDGES, NODEINDS, WEIGHTS)
0011 %   Specifies two or more points that must be traversed by the path, in the
0012 %   specified order.
0013 %
0014 %   % Create a simple tree graph, and compute shortest path
0015 %     [x y] = meshgrid([10 20 30], [10 20 30]);
0016 %     nodes = [x(:) y(:)];
0017 %     edges = [1 2;2 3;2 5;3 6; 4 5;4 7;5 8; 8 9];
0018 %     drawGraph(nodes, edges)
0019 %     axis equal; axis([0 40 0 40]);
0020 %     drawNodeLabels(nodes, 1:9)
0021 %     path = grShortestPath(nodes, edges, 1, 9);
0022 %     % same as:
0023 %     path = grShortestPath(nodes, edges, [1 9]);
0024 %
0025 %   See also
0026 %     graphs, grFindMaximalLengthPath
0027 %
0028 
0029 % ------
0030 % Author: David Legland
0031 % E-mail: david.legland@inrae.fr
0032 % Created: 2011-05-22, using Matlab 7.9.0.529 (R2009b)
0033 % Copyright 2011-2024 INRA - Cepia Software Platform
0034 
0035 % process the case where several node indices are specified in first arg.
0036 if length(ind0) > 1
0037     % following optional argument is edge values
0038     if exist('ind1', 'var')
0039         edgeWeights = ind1;
0040     else
0041         edgeWeights = ones(size(edges, 1), 1);
0042     end
0043     
0044     % concatenate path pieces
0045     nodePath = ind0(1);
0046     edgePath = size(0, 2);
0047     for i = 2:length(ind0)
0048         [node0, edge0] = grShortestPath(nodes, edges, ind0(i-1), ind0(i), edgeWeights);
0049         nodePath = [nodePath ; node0(2:end)]; %#ok<AGROW>
0050         edgePath = [edgePath ; edge0]; %#ok<AGROW>
0051     end
0052     
0053     return;
0054 end
0055 
0056 % ensure weights are defined
0057 if ~exist('edgeWeights', 'var')
0058     edgeWeights = ones(size(edges, 1), 1);
0059 end
0060 
0061 
0062 % check indices limits
0063 nNodes = size(nodes, 1);
0064 if max(ind0) > nNodes
0065     error('Start index exceed number of nodes in the graph');
0066 end
0067 if max(ind1) > nNodes
0068     error('End index exceed number of nodes in the graph');
0069 end
0070 
0071 
0072 %% Initialisations
0073 
0074 % consider infinite distance for all nodes
0075 dists = inf * ones(nNodes, 1);
0076 
0077 % initial node is at distance 0 by definition
0078 dists(ind0) = 0;
0079 
0080 % create an array of indices for the predessor of each node
0081 preds = zeros(nNodes, 1);
0082 preds(ind0) = 0;
0083 
0084 % allocate memory to store the subgraph, which is a tree
0085 edges2 = zeros(nNodes-1, 2);
0086 
0087 % create an array of node flags
0088 unprocessedNodeInds = 1:nNodes;
0089 
0090 edgeCount = 0;
0091 
0092 
0093 %% Iterate until all nodes are flagged to 1
0094 
0095 while ~isempty(unprocessedNodeInds)
0096     % choose unprocessed node with lowest distance
0097     [tmp, ind] = min(dists(unprocessedNodeInds)); %#ok<ASGLU>
0098     ind = unprocessedNodeInds(ind);
0099     ind = ind(1);
0100 
0101     % mark current node as processed
0102     unprocessedNodeInds(unprocessedNodeInds == ind) = [];
0103     
0104     % if the current node is the target, it is not necessary to continue...
0105     if ind == ind1
0106         break;
0107     end
0108     
0109     % find the index list of edges incident to current node
0110     adjEdgeInds = grAdjacentEdges(edges, ind);
0111     
0112     % select edges whose opposite node has not yet been processed
0113     inds2 = sum(ismember(edges(adjEdgeInds, :), unprocessedNodeInds), 2) > 0;
0114     adjEdgeInds = adjEdgeInds(inds2);
0115     
0116     % iterate over incident edges to update adjacent nodes
0117     for iNeigh = 1:length(adjEdgeInds)
0118         % extract index of current adjacent node
0119         edge = edges(adjEdgeInds(iNeigh), :);
0120         adjNodeInd = edge(~ismember(edge, ind));
0121         
0122         newDist = dists(ind) + edgeWeights(adjEdgeInds(iNeigh));
0123 %         dists(adjNodeInd) = min(dists(adjNodeInd), newDist);
0124         if newDist < dists(adjNodeInd)
0125             dists(adjNodeInd) = newDist;
0126             preds(adjNodeInd) = ind;
0127         end
0128     end
0129 
0130     % find the list of adjacent nodes
0131     adjNodeInds = unique(edges(adjEdgeInds, :));
0132     adjNodeInds(adjNodeInds == ind) = [];
0133     
0134     % choose the adjacent nodes with lowest distance, and add the
0135     % corresponding edges to the subgraph
0136     if ~isempty(adjNodeInds)
0137         minDist = min(dists(adjNodeInds));
0138         closestNodeInds = adjNodeInds(dists(adjNodeInds) <= minDist);
0139         for iCloseNode = 1:length(closestNodeInds)
0140             edgeCount = edgeCount + 1;
0141             edges2(edgeCount, :) = [ind closestNodeInds(iCloseNode)];
0142         end
0143     end
0144 end
0145 
0146 
0147 %% Path creation
0148 
0149 % create the path: start from end index, and identify successive set of
0150 % neighbor edges and nodes
0151 
0152 nodeInd = ind1;
0153 nodePath = nodeInd;
0154 edgePath = [];
0155 
0156 % find predecessors until we reach ind0 node
0157 while nodeInd ~= ind0
0158     newNodeInd = preds(nodeInd);
0159     nodePath = [nodePath ; newNodeInd]; %#ok<AGROW>
0160 
0161     % search the edge (both directions) in the list of edges
0162     e_tmp                 = [nodeInd newNodeInd];
0163     [~,edgeInd]           = ismember ([e_tmp; e_tmp(end:-1:1)], edges, 'rows');
0164     edgeInd(edgeInd == 0) = []; % erase the one that isn't there
0165     edgePath = [edgePath ; edgeInd]; %#ok<AGROW>
0166 
0167     nodeInd = newNodeInd;
0168 end
0169     
0170 % reverse the path
0171 nodePath = nodePath(end:-1:1);
0172 edgePath = edgePath(end:-1:1);
0173

Generated on Thu 21-Nov-2024 11:30:22 by m2html © 2003-2022