00001 /*!@file Beobot/Graph.C basic graph class can be both directed 00002 and undirected */ 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Christian Siagian <siagian@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Beobot/Graph.C $ 00035 // $Id $ 00036 // 00037 00038 #include "Beobot/Graph.H" 00039 #include "Image/Image.H" 00040 #include "Image/MathOps.H" 00041 #include <unistd.h> 00042 00043 #include "Raster/Raster.H" 00044 00045 // ###################################################################### 00046 Graph::Graph(): 00047 itsNodes(), 00048 itsEdges(), 00049 itsDirectedAdjecencyList(), 00050 itsDirectedAdjecencyCostList(), 00051 itsDirectedAdjecencyInEdgeList(), 00052 itsDirectedAdjecencyOutEdgeList(), 00053 itsUndirectedAdjecencyList(), 00054 itsUndirectedAdjecencyCostList(), 00055 itsUndirectedAdjecencyEdgeList(), 00056 itsDirectedPathList(), 00057 itsUndirectedPathList() 00058 { 00059 itsDistanceMatrixComputed = false; 00060 } 00061 00062 // ###################################################################### 00063 Graph::Graph(std::vector<rutz::shared_ptr<Node> > nodes, 00064 std::vector<rutz::shared_ptr<Edge> > edges): 00065 itsNodes(), 00066 itsEdges(), 00067 itsDirectedAdjecencyList(), 00068 itsDirectedAdjecencyCostList(), 00069 itsDirectedAdjecencyInEdgeList(), 00070 itsDirectedAdjecencyOutEdgeList(), 00071 itsUndirectedAdjecencyList(), 00072 itsUndirectedAdjecencyCostList(), 00073 itsUndirectedAdjecencyEdgeList(), 00074 itsDirectedPathList(), 00075 itsUndirectedPathList() 00076 { 00077 for(uint i = 0; i < nodes.size(); i++) 00078 itsNodes.push_back(nodes[i]); 00079 00080 for(uint i = 0; i < edges.size(); i++) 00081 itsEdges.push_back(edges[i]); 00082 00083 itsDistanceMatrixComputed = false; 00084 } 00085 00086 // ###################################################################### 00087 Graph::~Graph() 00088 { } 00089 00090 // ###################################################################### 00091 void Graph::addNode(rutz::shared_ptr<Node> node) 00092 { 00093 itsNodes.push_back(node); 00094 } 00095 00096 // ###################################################################### 00097 void Graph::addEdge(rutz::shared_ptr<Edge> edge) 00098 { 00099 itsEdges.push_back(edge); 00100 } 00101 00102 // ###################################################################### 00103 void Graph::computeAdjecencyList() 00104 { 00105 itsDirectedAdjecencyList.resize(itsNodes.size()); 00106 itsDirectedAdjecencyCostList.resize(itsNodes.size()); 00107 itsDirectedAdjecencyInEdgeList.resize(itsNodes.size()); 00108 itsDirectedAdjecencyOutEdgeList.resize(itsNodes.size()); 00109 00110 itsUndirectedAdjecencyList.resize(itsNodes.size()); 00111 itsUndirectedAdjecencyCostList.resize(itsNodes.size()); 00112 itsUndirectedAdjecencyEdgeList.resize(itsNodes.size()); 00113 00114 // for each edge get the nodes 00115 for(uint i = 0; i < itsEdges.size(); i++) 00116 { 00117 uint sind = itsEdges[i]->getSourceNode()->getIndex(); 00118 uint dind = itsEdges[i]->getDestNode()->getIndex(); 00119 float cost = itsEdges[i]->getCost(); 00120 LINFO("[%d -> %d]: %f", sind, dind, cost); 00121 00122 // adjecency list: 00123 00124 //for directed case 00125 itsDirectedAdjecencyList[sind].push_back(dind); 00126 itsDirectedAdjecencyCostList[sind].push_back(cost); 00127 00128 itsDirectedAdjecencyInEdgeList[dind].push_back(i); 00129 itsDirectedAdjecencyOutEdgeList[sind].push_back(i); 00130 00131 //for undirected case 00132 itsUndirectedAdjecencyList[sind].push_back(dind); 00133 itsUndirectedAdjecencyList[dind].push_back(sind); 00134 itsUndirectedAdjecencyCostList[sind].push_back(cost); 00135 itsUndirectedAdjecencyCostList[dind].push_back(cost); 00136 00137 itsUndirectedAdjecencyEdgeList[dind].push_back(i); 00138 itsUndirectedAdjecencyEdgeList[sind].push_back(i); 00139 } 00140 } 00141 00142 // ###################################################################### 00143 void Graph::computeDistances() 00144 { 00145 // to avoid flag in getDistance() 00146 itsDistanceMatrixComputed = false; 00147 uint nnode = itsNodes.size(); 00148 00149 // create distance matrix 00150 itsDirectedDistanceMatrix.resize(nnode, nnode); 00151 itsDirectedPathList.resize(nnode); 00152 itsUndirectedDistanceMatrix.resize(nnode, nnode); 00153 itsUndirectedPathList.resize(nnode); 00154 for(uint i = 0; i < nnode; i++) 00155 { 00156 itsDirectedPathList[i].resize(nnode); 00157 itsUndirectedPathList[i].resize(nnode); 00158 } 00159 00160 for(uint i = 0; i < nnode; i++) 00161 { 00162 for(uint j = 0; j < nnode; j++) 00163 { 00164 // directed case 00165 std::vector<uint> dedges; 00166 float ddist = getDirectedDistance(i,j, dedges); 00167 itsDirectedDistanceMatrix.setVal(i,j, ddist); 00168 itsDirectedPathList[i][j] = dedges; 00169 00170 // undirected case 00171 std::vector<uint> uedges; 00172 float udist = getUndirectedDistance(i,j, uedges); 00173 itsUndirectedDistanceMatrix.setVal(i,j, udist); 00174 itsUndirectedPathList[i][j] = uedges; 00175 } 00176 } 00177 itsDistanceMatrixComputed = true; 00178 } 00179 00180 // ###################################################################### 00181 float Graph::getDirectedDistance(uint a, uint b) 00182 { 00183 std::vector<uint> edges; 00184 return getDirectedDistance(a, b, edges); 00185 } 00186 00187 // ###################################################################### 00188 float Graph::getDirectedDistance 00189 (uint a, uint b, std::vector<uint> &edges) 00190 { 00191 ASSERT(a < itsNodes.size() && b < itsNodes.size()); 00192 if(a == b) return 0.0F; 00193 00194 if(itsDistanceMatrixComputed) 00195 { 00196 edges.clear(); 00197 for(uint i = 0; i < itsDirectedPathList[a][b].size(); i++) 00198 edges.push_back(itsDirectedPathList[a][b][i]); 00199 return itsDirectedDistanceMatrix[Point2D<int>(a,b)]; 00200 } 00201 00202 uint nnode = itsNodes.size(); 00203 std::vector<float> edist(nnode); 00204 std::vector<uint> epath(nnode); 00205 00206 // NOTE: this is Dijkstra algorithm 00207 // we can't have negative edges 00208 for(uint i = 0; i < nnode; i++) edist[i] = -1.0F; 00209 std::vector<bool> selected(nnode); 00210 for(uint i = 0; i < nnode; i++) selected[i] = false; 00211 00212 // Directed edges 00213 uint nsadj = itsDirectedAdjecencyList[a].size(); 00214 for(uint i = 0; i < nsadj; i++) 00215 { 00216 uint adjnode = itsDirectedAdjecencyList[a][i]; 00217 edist[adjnode] = itsDirectedAdjecencyCostList[a][i]; 00218 epath[adjnode] = itsDirectedAdjecencyOutEdgeList[a][i]; 00219 } 00220 edist[a] = 0.0F; selected[a] = true; 00221 00222 //for(uint ii = 0; ii < edist.size(); ii++) 00223 // LINFO("[%d]: %d %f",ii, int(selected[ii]), edist[ii]); 00224 00225 // while the minimum vertex is not our destination 00226 // or all the queue minimums are negative (can't reach anything else) 00227 // for un-connected graph 00228 uint mindex = a; bool end = false; 00229 while(mindex != b && !end) 00230 { 00231 // find the minimum distance in the queue 00232 float mindist = -1.0F; 00233 for(uint i = 0; i < nnode; i++) 00234 if(!selected[i] && edist[i] != -1.0F && 00235 (mindist == -1.0F || mindist > edist[i])) 00236 { 00237 mindist = edist[i]; mindex = i; 00238 //LINFO("in: %d: mindex: %d mindist: %f", i, mindex, mindist); 00239 } 00240 00241 //LINFO("min index[%d] %f", mindex, edist[mindex]); 00242 00243 // if we still have a reacheable node 00244 if(mindist != -1.0F) 00245 { 00246 selected[mindex] = true; 00247 00248 uint nadj = itsDirectedAdjecencyList[mindex].size(); 00249 for(uint i = 0; i < nadj; i++) 00250 { 00251 uint eindex = itsDirectedAdjecencyOutEdgeList[mindex][i]; 00252 uint adjindex = itsDirectedAdjecencyList[mindex][i]; 00253 float cost = itsDirectedAdjecencyCostList[mindex][i]; 00254 00255 //LINFO("eindex: %d adjindex: %d cost: %f", eindex, adjindex, cost); 00256 00257 if(edist[adjindex] == -1.0F || 00258 edist[adjindex] > edist[mindex] + cost) 00259 { 00260 //LINFO("relaxing: %d: %f -> %f", adjindex, 00261 // edist[adjindex], edist[mindex] + cost); 00262 edist[adjindex] = edist[mindex] + cost; 00263 epath[adjindex] = eindex; 00264 00265 //LINFO("edist[%d]: %f epath[%d]: %d", 00266 // adjindex, edist[adjindex], 00267 // adjindex, epath[adjindex]); 00268 } 00269 } 00270 } 00271 else { end = true; } 00272 00273 //for(uint ii = 0; ii < edist.size(); ii++) 00274 // LINFO("[%d]: %d %f",ii, int(selected[ii]), edist[ii]); 00275 } 00276 00277 // use the distances to calculate the list of edges 00278 edges.clear(); 00279 00280 // if node b is not unreachable 00281 if(edist[b] != -1.0F) 00282 { 00283 std::vector<uint> tEdges; 00284 // backtrack from the destination 00285 uint index = b; 00286 while(index != a) 00287 { 00288 tEdges.push_back(epath[index]); 00289 //LINFO("index: %d: epath: %d",index, epath[index]); 00290 index = getEdge(epath[index])->getSourceNode()->getIndex(); 00291 } 00292 for(int i = tEdges.size()-1; i >= 0; i--) 00293 edges.push_back(tEdges[i]); 00294 } 00295 00296 return edist[b]; 00297 } 00298 00299 // ###################################################################### 00300 float Graph::getUndirectedDistance(uint a, uint b) 00301 { 00302 std::vector<uint> edges; 00303 return getUndirectedDistance(a, b, edges); 00304 } 00305 00306 // ###################################################################### 00307 float Graph::getUndirectedDistance 00308 (uint a, uint b, std::vector<uint> &edges) 00309 { 00310 ASSERT(a < itsNodes.size() && b < itsNodes.size()); 00311 if(a == b) return 0.0F; 00312 //LINFO("a: %d, b: %d", a, b); 00313 00314 if(itsDistanceMatrixComputed) 00315 { 00316 edges.clear(); 00317 for(uint i = 0; i < itsUndirectedPathList[a][b].size(); i++) 00318 { 00319 edges.push_back(itsUndirectedPathList[a][b][i]); 00320 //LINFO("edge[%d]: %d", i, edges[i]); 00321 } 00322 return itsUndirectedDistanceMatrix[Point2D<int>(a,b)]; 00323 } 00324 00325 uint nnode = itsNodes.size(); 00326 std::vector<float> edist(nnode); 00327 std::vector<uint> epath(nnode); 00328 00329 // NOTE: this is Dijkstra algorithm 00330 // we can't have negative edges 00331 for(uint i = 0; i < nnode; i++) edist[i] = -1.0F; 00332 std::vector<bool> selected(nnode); 00333 for(uint i = 0; i < nnode; i++) selected[i] = false; 00334 00335 // undirected edges 00336 uint nsadj = itsUndirectedAdjecencyList[a].size(); 00337 //LINFO("nsadj: %d", nsadj); 00338 for(uint i = 0; i < nsadj; i++) 00339 { 00340 uint adjnode = itsUndirectedAdjecencyList[a][i]; 00341 edist[adjnode] = itsUndirectedAdjecencyCostList[a][i]; 00342 epath[adjnode] = itsUndirectedAdjecencyEdgeList[a][i]; 00343 } 00344 edist[a] = 0.0F; selected[a] = true; 00345 00346 // for(uint ii = 0; ii < edist.size(); ii++) 00347 // LINFO("[%d]:sel:%d %f ep:%d", 00348 // ii, int(selected[ii]), edist[ii], epath[ii]); 00349 00350 // while the minimum vertex is not our destination 00351 // or all the queue minimums are negative (can't reach anything else) 00352 // for un-connected graph 00353 uint mindex = a; bool end = false; 00354 while(mindex != b && !end) 00355 { 00356 // find the minimum distance in the queue 00357 float mindist = -1.0F; 00358 for(uint i = 0; i < nnode; i++) 00359 if(!selected[i] && edist[i] != -1.0F && 00360 (mindist == -1.0F || mindist > edist[i])) 00361 { 00362 mindist = edist[i]; mindex = i; 00363 //LINFO("in: %d: mindex: %d mindist: %f", i, mindex, mindist); 00364 } 00365 00366 //LINFO("min index[%d] %f", mindex, edist[mindex]); 00367 00368 // if we still have a reacheable node 00369 if(mindist != -1.0F) 00370 { 00371 selected[mindex] = true; 00372 00373 uint nadj = itsUndirectedAdjecencyList[mindex].size(); 00374 for(uint i = 0; i < nadj; i++) 00375 { 00376 uint eindex = itsUndirectedAdjecencyEdgeList[mindex][i]; 00377 uint adjindex = itsUndirectedAdjecencyList[mindex][i]; 00378 float cost = itsUndirectedAdjecencyCostList[mindex][i]; 00379 00380 if(edist[adjindex] == -1.0F || 00381 edist[adjindex] > edist[mindex] + cost) 00382 { 00383 //LINFO("relaxing: %d: %f -> %f", adjindex, 00384 // edist[adjindex], edist[mindex] + cost); 00385 edist[adjindex] = edist[mindex] + cost; 00386 epath[adjindex] = eindex; 00387 } 00388 } 00389 } 00390 else { end = true; } 00391 00392 //for(uint ii = 0; ii < edist.size(); ii++) 00393 // LINFO("[%d]: %d %f",ii, int(selected[ii]), edist[ii]); 00394 } 00395 00396 // use the distances to calculate the list of edges 00397 edges.clear(); 00398 00399 // if node b is not unreachable 00400 if(edist[b] != -1.0F) 00401 { 00402 std::vector<uint> tEdges; 00403 // backtrack from the destination 00404 uint index = b; 00405 while(index != a) 00406 { 00407 tEdges.push_back(epath[index]); 00408 uint is = getEdge(epath[index])->getSourceNode()->getIndex(); 00409 uint id = getEdge(epath[index])->getDestNode()->getIndex(); 00410 if(index == is) index = id; 00411 else index = is; 00412 //LINFO("edge index: %d",index); 00413 } 00414 00415 for(int i = tEdges.size()-1; i >= 0; i--) 00416 edges.push_back(tEdges[i]); 00417 } 00418 return edist[b]; 00419 } 00420 00421 // ###################################################################### 00422 float Graph::getMaxDirectedDistance() 00423 { 00424 float min, max; 00425 getMinMax(itsDirectedDistanceMatrix, min, max); 00426 if(min == -1.0F) return -1.0F; 00427 else return max; 00428 } 00429 00430 // ###################################################################### 00431 float Graph::getMaxUndirectedDistance() 00432 { 00433 float min, max; 00434 getMinMax(itsUndirectedDistanceMatrix, min, max); 00435 if(min == -1.0F) return -1.0F; 00436 else return max; 00437 } 00438 00439 // ###################################################################### 00440 std::vector<uint> Graph::getDirectedPath(uint a, uint b) 00441 { 00442 std::vector<uint> edges; 00443 00444 // if distance matrix is already computed 00445 if(itsDistanceMatrixComputed) return itsDirectedPathList[a][b]; 00446 else 00447 { 00448 getDirectedDistance(a, b, edges); 00449 return edges; 00450 } 00451 } 00452 00453 // ###################################################################### 00454 std::vector<uint> Graph::getUndirectedPath(uint a, uint b) 00455 { 00456 std::vector<uint> edges; 00457 00458 // if distance matrix is already computed 00459 if(itsDistanceMatrixComputed) return itsUndirectedPathList[a][b]; 00460 else 00461 { 00462 getUndirectedDistance(a, b, edges); 00463 return edges; 00464 } 00465 } 00466 00467 // ###################################################################### 00468 std::vector<uint> Graph::getEdges(rutz::shared_ptr<Node> n) 00469 { 00470 std::vector<uint> res; 00471 00472 // for each edge get the nodes 00473 for(uint i = 0; i < itsEdges.size(); i++) 00474 { 00475 00476 //res.push_back(); 00477 } 00478 LFATAL("not yet implemented"); 00479 00480 return res; 00481 } 00482 00483 // ###################################################################### 00484 float Graph::getAngle 00485 (rutz::shared_ptr<Edge> e1, rutz::shared_ptr<Edge> e2) 00486 { 00487 // get the end coordinates of each edge 00488 Point2D<int> s1 = e1->getSourceNode()->getCoordinate(); 00489 Point2D<int> d1 = e1->getDestNode()->getCoordinate(); 00490 Point2D<int> s2 = e2->getSourceNode()->getCoordinate(); 00491 Point2D<int> d2 = e2->getDestNode()->getCoordinate(); 00492 LDEBUG("(s1(%d,%d)-d1(%d,%d))-----(s2(%d,%d)-d2(%d,%d))", 00493 s1.i, s1.j,d1.i, d1.j, s2.i, s2.j,d2.i, d2.j); 00494 00495 // calculate differences 00496 float xD1 = d1.i - s1.i; 00497 float xD2 = d2.i - s2.i; 00498 float yD1 = d1.j - s1.j; 00499 float yD2 = d2.j - s2.j; 00500 00501 // calculate the lengths of the two lines 00502 float len1 = sqrt(xD1*xD1+yD1*yD1); 00503 float len2 = sqrt(xD2*xD2+yD2*yD2); 00504 00505 float dot = (xD1*xD2+yD1*yD2); // dot product 00506 float cross = (xD1*yD2-xD2*yD1); // cross product 00507 00508 // calculate angle between the two lines 00509 float ang = atan2(cross/(len1*len2), dot/(len1*len2)); 00510 return ang; 00511 } 00512 00513 // ###################################################################### 00514 /* So things look consistent in everyone's emacs... */ 00515 /* Local Variables: */ 00516 /* indent-tabs-mode: nil */ 00517 /* End: */