eg_dijkstra.c

Go to the documentation of this file.
00001 /* EGlib "Efficient General Library" provides some basic structures and
00002  * algorithms commons in many optimization algorithms.
00003  *
00004  * Copyright (C) 2005 Daniel Espinoza and Marcos Goycoolea.
00005  * 
00006  * This library is free software; you can redistribute it and/or modify it
00007  * under the terms of the GNU Lesser General Public License as published by the
00008  * Free Software Foundation; either version 2.1 of the License, or (at your
00009  * option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful, but 
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
00013  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
00014  * License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this library; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
00019  * */
00020 #include "eg_dijkstra.h"
00021 
00022 /*****************************************************************************
00023  * EGpartialDijkstra                                                         *
00024  *                                                                           *
00025  * This algorithm requires the following 5 offsets:                          *
00026  *                                                                           *
00027  * [0]  name:  dist    where: node_data  type: void*                         *
00028  *                                                                           *
00029  * This value is used to store the distance of the node in question to s. To *
00030  * access the value simply cast the memory address to type (EGdijkstraCost_t).     *
00031  *                                                                           *
00032  * [1]  name: ndist    where: node_data  type: void*                         *
00033  *                                                                           *
00034  * This value is used to store the number of edges in the current optimal    *
00035  * path from the node to s.                                                  *
00036  *                                                                           *
00037  * [3]  name: marker   where: node_data  type: void*                         *
00038  *                                                                           *
00039  * This value is used to indicate the dijkstra iteration in which the node   *
00040  * was permanently labeled. If the node has not been permanently labeled the *
00041  * value of this field is UINT_MAX.                                           *
00042  *                                                                           *
00043  * [4]  name: heap_cn  where: node_data  type: void*                         *
00044  *                                                                           *
00045  * This value is used to hold the memory location of the heap connector used *
00046  * by the algorithm. After the run this field may-or-may-not mean anything.  *
00047  * If the value of this field is 0 it means that it was never used in the    *
00048  * algorithm, hence the distance and ndistance field values will be          *
00049  * meaningless.                                                              *
00050  *                                                                           *
00051  * [2]  name: father   where: node_data  type: void*                         *
00052  *                                                                           *
00053  * This value is used to point to the EGdGraphEdge_t of the edge which pre-  *
00054  * cedes the node in question in the best solution found so far.             *
00055  *                                                                           *
00056  * [5]  name: ecost    where: edge_data  type: (EGdijkstraCost_t)                  *
00057  *                                                                           *
00058  * This value is used to store the length of the edge in question.           *
00059  *                                                                           *
00060  *****************************************************************************/
00061 
00062 int EGpartialDijkstra (EGdGraphNode_t * s,
00063                        EGdGraphNode_t * t,
00064                        EGdijkstraCost_t ubound,
00065                        size_t * os,
00066                        EGheap_t * my_heap,
00067                        EGdGraph_t * G)
00068 {
00069   unsigned int tmarked = 0;
00070   EGdijkstraCost_t value = EGdijkstraToCost (0.0);
00071   EGdGraphEdge_t *e;
00072   EGdGraphNode_t *best_node;
00073   EGlistNode_t *node_it,
00074    *edge_it;
00075   EGheapConnector_t *h_c;
00076 
00077   EGmemPool_t *mem;
00078 
00079   mem = s->out_edges->mempool;
00080 
00081 #if EG_DIJKSTRA_NEGATIVE_CHECK
00082   for (node_it = G->nodes->begin; node_it; node_it = node_it->next)
00083   {
00084     best_node = (EGdGraphNode_t *) (node_it->this);
00085     for (edge_it = best_node->out_edges->begin; edge_it;
00086          edge_it = edge_it->next)
00087     {
00088       e = (EGdGraphEdge_t *) (edge_it->this);
00089       if (EGdijkstraCostToLf (EGdijkstraGetEdgeLength (e, os)) < 0.0)
00090       {
00091         fprintf (stderr,
00092                  "\n\nwarning: found negative weight edge in dijkstra of value %lf.\n",
00093                  EGdijkstraCostToLf (EGdijkstraGetEdgeLength (e, os)));
00094         TEST (1, "negative edge");
00095         return 1;
00096       }
00097     }
00098 
00099   }
00100 #endif
00101 
00102   /* For every node in the graph, we initialize its distance to 's' to be as  */
00103   /* great as possible; that is, to EG_DIJ_COST_MAX.                          */
00104 
00105   if (t)
00106     EGdijkstraSetDist (t, os, EG_DIJKSTRA_COST_MAX);
00107   for (node_it = G->nodes->begin; node_it; node_it = node_it->next)
00108   {
00109     EGdijkstraSetHeapConnector (node_it->this, os, 0);
00110     EGdijkstraSetMarker (node_it->this, os, UINT_MAX);
00111   }
00112 
00113   /* We use the heap to keep track of the 'un-marked' nodes and quickly       *
00114    * find the 'closest' node to 's'. We clear it, and initialize it with only *
00115    * 's' belonging to it.                                                     */
00116 
00117   EGheapClear (my_heap, mem);
00118   h_c = EGheapInsert (my_heap, s, 0, mem);
00119 
00120   /* The distance from 's' to itself is '0'.                                  */
00121   EGdijkstraSetDist (s, os, EGdijkstraToCost (0.0));
00122 
00123   /* The number of edges in an optimal path from 's' to 's' is '0'.           */
00124   EGdijkstraSetNdist (s, os, 0);
00125 
00126   /* Node 's' has no father, hence the pointer is set to NULL.                */
00127   EGdijkstraSetFather (s, os, 0);
00128 
00129   /* Node 's' uses 'h_c' as its heap connector.                               */
00130   EGdijkstraSetHeapConnector (s, os, h_c);
00131 
00132   while (my_heap->size != 0)
00133   {
00134 
00135     /* Find the unmarked node in the graph that is closest to s. We remove    *
00136      * this node from the heap, and mark it.                                  */
00137 
00138     h_c = EGheapGetMin (my_heap);
00139     best_node = (EGdGraphNode_t *) (h_c->this);
00140     EGheapDeleteMin (my_heap, mem);
00141     EGdijkstraSetMarker (best_node, os, tmarked);
00142     tmarked += 1;
00143     EGdijkstraSetHeapConnector (best_node, os, 0);
00144 
00145     /* If 't' is among the closest nodes to 's' then we are done.             */
00146 
00147     /* if ( best_node == t ) */
00148     /* if ( EGdijkstraGetDist(best_node, os) == EGdijkstraGetDist(t, os) )  */
00149     if (t
00150         &&
00151         EGdijkstraCostIsLess (EGdijkstraCostSub
00152                               (EGdijkstraGetDist (t, os),
00153                                EGdijkstraGetDist (best_node, os)),
00154                               EG_DIJKSTRA_OPTERROR))
00155       break;
00156 
00157     if (EGdijkstraCostIsLess (ubound, EGdijkstraGetDist (best_node, os)))
00158       return 0;
00159 
00160     /* We update the values of the nodes adjacent to 'best_node'. In order    *
00161      * to do this we loop through its incident edges.                         */
00162 
00163     for (edge_it = best_node->out_edges->begin; edge_it;
00164          edge_it = edge_it->next)
00165     {
00166 
00167       e = (EGdGraphEdge_t *) (edge_it->this);
00168       TESTL (5, EGdijkstraCostToLf (EGdijkstraGetEdgeLength (e, os)) < 0,
00169              "Negative edge");
00170       value =
00171         EGdijkstraCostAdd (EGdijkstraGetDist (best_node, os),
00172                            EGdijkstraGetEdgeLength (e, os));
00173 
00174       /* If e->head's distance to 's' is set to EG_DIJ_COST_MAX it means that *
00175        * its not in the heap. In this case we correct its value and add it.   */
00176 
00177       if (EGdijkstraGetMarker (e->head, os) == UINT_MAX)
00178       {
00179         EGdijkstraSetFather (e->head, os, e);
00180         EGdijkstraSetNdist (e->head, os,
00181                             EGdijkstraGetNdist (best_node, os) + 1);
00182         EGdijkstraSetDist (e->head, os, value);
00183         h_c = EGheapInsert (my_heap, e->head, value, mem);
00184         EGdijkstraSetHeapConnector (e->head, os, h_c);
00185         EGdijkstraSetMarker (e->head, os, UINT_MAX - 1);
00186       }
00187 
00188       /* If e->head's distance to 's' already has a value, we check if going  *
00189        * through 'best_node' results in a shorter distance. If so, we update  *
00190        * the parameters of 'e->head' and reorganize the heap.                 */
00191 
00192       else
00193         if (EGdijkstraCostIsLess
00194             (EGdijkstraCostAdd (value, EG_DIJKSTRA_EPSILON),
00195              EGdijkstraGetDist (e->head, os)))
00196       {
00197 
00198         EGdijkstraSetFather (e->head, os, e);
00199         EGdijkstraSetNdist (e->head, os,
00200                             EGdijkstraGetNdist (best_node, os) + 1);
00201         EGdijkstraSetDist (e->head, os, value);
00202         EGheapDecreaseVal (my_heap, EGdijkstraGetHeapConnector (e->head, os),
00203                            value);
00204       }
00205 
00206     }
00207 
00208   }
00209 
00210   return 0;
00211 
00212 }
00213 
00214 int EGdijkstraCheckOptimality (EGdGraphNode_t * s,
00215                                EGdGraphNode_t * t,
00216                                EGdijkstraCost_t ubound,
00217                                size_t * os,
00218                                EGdGraph_t * G)
00219 {
00220 
00221   EGlistNode_t *n_it,
00222    *e_it;
00223   EGdGraphEdge_t *e;
00224   EGdGraphNode_t *n;
00225   unsigned int hid,
00226     tid;
00227   double vh,
00228     vt,
00229     ve;
00230 
00231   s = 0;
00232   t = 0;
00233   ubound = 0;
00234 
00235   for (n_it = G->nodes->begin; n_it; n_it = n_it->next)
00236   {
00237     n = (EGdGraphNode_t *) (n_it->this);
00238     for (e_it = n->out_edges->begin; e_it; e_it = e_it->next)
00239     {
00240       e = (EGdGraphEdge_t *) (e_it->this);
00241       if (EGdijkstraGetDist (e->head, os) >
00242           (EGdijkstraGetDist (e->tail, os) + EGdijkstraGetEdgeLength (e, os)))
00243       {
00244         hid = e->head->id;
00245         tid = e->tail->id;
00246         vh = EGdijkstraCostToLf (EGdijkstraGetDist (e->head, os));
00247         vt = EGdijkstraCostToLf (EGdijkstraGetDist (e->tail, os));
00248         ve = EGdijkstraCostToLf (EGdijkstraGetEdgeLength (e, os));
00249         fprintf (stderr,
00250                  "c(%u) = %lf  c(%u) = %lf  c(%u, %u) = %lf  c(%u) + c(%u,%u)  = %lf\n",
00251                  tid, vt, hid, vh, tid, hid, ve, tid, tid, hid, vt + ve);
00252         return 1;
00253       }
00254     }
00255   }
00256 
00257   return 0;
00258 
00259 }
00260 
00261 int EGdijkstraExtractSolution (EGdGraphEdge_t ** path,
00262                                unsigned int *npath,
00263                                EGdGraphNode_t * s,
00264                                EGdGraphNode_t * t,
00265                                size_t * os)
00266 {
00267 
00268   EGdGraphEdge_t *e;
00269   EGdGraphNode_t *n;
00270   unsigned int pos;
00271 
00272   s = 0;
00273   *npath = 0;
00274 
00275   n = t;
00276   pos = EGdijkstraGetNdist (t, os);
00277   while (pos)
00278   {
00279     e = EGdijkstraGetFather (n, os);
00280     path[pos - 1] = e;
00281     n = e->tail;
00282     pos = EGdijkstraGetNdist (n, os);
00283     *npath += 1;
00284   }
00285 
00286   return 0;
00287 
00288 }

Generated on Mon Jan 30 08:48:52 2006 for EGlib by  doxygen 1.4.5