Bellman_Ford.H

00001 
00002 /*
00003   This file is part of Aleph system
00004 
00005   Copyright (c) 2002, 2003, 2004, 2005, 2006
00006   UNIVERSITY LOS ANDES (ULA) Merida - REPÚBLICA BOLIVARIANA DE VENEZUELA  
00007 
00008   - Center of Studies in Microelectronics & Distributed Systems (CEMISID) 
00009   - ULA Computer Science Department
00010   - FUNDACITE Mérida - Ministerio de Ciencia y Tecnología
00011 
00012   PERMISSION TO USE, COPY, MODIFY AND DISTRIBUTE THIS SOFTWARE AND ITS
00013   DOCUMENTATION IS HEREBY GRANTED, PROVIDED THAT BOTH THE COPYRIGHT
00014   NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES OF THE
00015   SOFTWARE, DERIVATIVE WORKS OR MODIFIED VERSIONS, AND ANY PORTIONS
00016   THEREOF, AND THAT BOTH NOTICES APPEAR IN SUPPORTING DOCUMENTATION.
00017 
00018   Aleph is distributed in the hope that it will be useful, but WITHOUT
00019   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00020   or FITNESS FOR A PARTICULAR PURPOSE.
00021 
00022   UNIVERSIDAD DE LOS ANDES requests users of this software to return to 
00023 
00024   Leandro Leon
00025   CEMISID 
00026   Ed La Hechicera 
00027   3er piso, ala sur
00028   Facultad de Ingenieria 
00029   Universidad de Los Andes 
00030   Merida - REPÚBLICA BOLIVARIANA DE VENEZUELA    or
00031 
00032   lrleon@ula.ve
00033 
00034   any improvements or extensions that they make and grant Universidad 
00035   de Los Andes (ULA) the rights to redistribute these changes. 
00036 
00037   Aleph is (or was) granted by: 
00038   - Consejo de Desarrollo Cientifico, Humanistico, Tecnico de la ULA 
00039     (CDCHT)
00040   - Fundacite Mérida
00041 */
00042 
00043 
00044 # ifndef BELLMAN_FORD_H
00045 # define BELLMAN_FORD_H
00046 
00047 # include <tpl_dynListQueue.H>
00048 # include <tpl_graph.H>
00049 
00050 namespace Aleph {
00051 
00052 
00053 # define NI(p) (static_cast<Bellman_Ford_Node_Info<GT, Distance>*>(NODE_COOKIE(p)))
00054 # define IDX(p) (NI(p)->idx)
00055 # define ACU(p) (NI(p)->acum)
00056     template <class GT, class Distance>
00057 struct Bellman_Ford_Node_Info
00058 {
00059   int                              idx;
00060   typename Distance::Distance_Type acum;
00061 };
00133     template <class GT, class Distance, class Compare, class Plus> inline
00134 bool bellman_ford_min_spanning_tree(GT &                g,
00135                                     typename GT::Node * start_node, 
00136                                     GT &                tree)
00137 {
00138   if (not g.is_digraph())
00139     throw std::domain_error("Bellman-Ford algorithm only operates on digraphs");
00140   tree.clear_graph(); // limpiar árbol abarcador destino 
00141   DynArray<typename GT::Node*> pred;
00142   DynArray<typename GT::Arc*> arcs;
00143   {
00144     typename GT::Node_Iterator it(g);
00145 
00146     for (int i = 0; it.has_current(); ++i, it.next())
00147       {
00148         typename GT::Node * p = it.get_current_node();
00149 
00150         pred[i] = NULL; 
00151         arcs[i] = NULL;
00152 
00153         g.reset_bit(p, Aleph::Min); // colocar bit en cero
00154 
00155             // apartar memoria para cookie (índice y acumulado en distancia)
00156         Bellman_Ford_Node_Info <GT, Distance> * ptr = 
00157           new Bellman_Ford_Node_Info <GT, Distance>;
00158 
00159         NODE_BITS(p).set_bit(Min, false); 
00160         NODE_BITS(p).set_bit(Breadth_First, false); 
00161         NODE_COOKIE(p) = ptr;
00162 
00163             // inicializar campos del cookie
00164         ptr->idx  = i;
00165         ptr->acum = Distance::Max_Distance;
00166     }
00167   }
00168   ACU(start_node) = Distance::Zero_Distance;
00169   g.reset_bit_arcs(Min); 
00170   for (int i = 0, n = g.get_num_nodes() - 1; i < n; ++i)
00171         // recorrer los arcos para evaluar si relajamiento
00172     for (typename GT::Arc_Iterator it(g); it.has_current(); it.next())
00173       {
00174         typename GT::Arc * arc = it.get_current_arc();
00175 
00176         typename GT::Node * src = g.get_src_node(arc);
00177         typename GT::Node * tgt = g.get_tgt_node(arc);
00178 
00179         const typename Distance::Distance_Type & dist =  Distance () (arc);
00180 
00181         const typename Distance::Distance_Type & acum_src = ACU(src);
00182 
00183         typename Distance::Distance_Type & acum_tgt = ACU(tgt);
00184 
00185         const typename Distance::Distance_Type sum = Plus () (acum_src, dist);
00186 
00187         if (Compare() (sum, acum_tgt))
00188           {
00189             const int & idx = IDX(tgt);
00190 
00191             pred[idx] = src;
00192             arcs[idx] = arc;
00193             acum_tgt  = sum;
00194           }
00195       }
00196   bool ret_val = true;
00197 
00198       // recorrer todos los arcos en búsqueda de un ciclo negativo
00199   for (typename GT::Arc_Iterator it(g); it.has_current(); it.next())
00200     {
00201       typename GT::Arc * arc = it.get_current_arc();
00202 
00203       typename GT::Node * src = g.get_src_node(arc);
00204       typename GT::Node * tgt = g.get_tgt_node(arc);
00205 
00206       const typename Distance::Distance_Type & dist     = Distance () (arc);
00207       const typename Distance::Distance_Type & acum_src = ACU(src);
00208       const typename Distance::Distance_Type & acum_tgt = ACU(tgt);
00209       const typename Distance::Distance_Type sum        = Plus ()(acum_src, dist);
00210 
00211       if (Compare() (sum, acum_tgt)) // ¿lograría modificarse tgt?
00212         {
00213           ret_val = false; // se detectó un ciclo negativo
00214           break;
00215         }
00216     }
00217   if (not ret_val) // ¿hay ciclos negativos?
00218     {    // liberar memoria de los cookies de los nodos
00219       for (typename GT::Node_Iterator it(g); it.has_current(); it.next())
00220         delete NI(it.get_current_node());
00221 
00222       return false;
00223     }
00224   for (int i = 0; i < g.get_num_nodes(); ++i)
00225     {
00226       typename GT::Arc * garc = arcs[i];
00227 
00228       if (garc == NULL)
00229         continue;
00230 
00231       typename GT::Node * gsrc = g.get_src_node(garc);
00232       typename GT::Node * tsrc = NULL;
00233       if (IS_NODE_VISITED(gsrc, Min))
00234         tsrc = static_cast<typename GT::Node*>(NODE_COOKIE(gsrc));
00235       else
00236         {
00237           NODE_BITS(gsrc).set_bit(Min, true); // marcar bit
00238 
00239           delete NI(gsrc);
00240 
00241           tsrc = tree.insert_node(gsrc->get_info());
00242           GT::map_nodes(gsrc, tsrc);
00243         }
00244 
00245       typename GT::Node * gtgt = g.get_tgt_node(garc);
00246       typename GT::Node * ttgt = NULL;
00247       if (IS_NODE_VISITED(gtgt, Min))
00248         ttgt = static_cast<typename GT::Node*>(NODE_COOKIE(gtgt));
00249       else
00250         {
00251           NODE_BITS(gtgt).set_bit(Min, true); // marcar bit
00252 
00253           delete NI(gtgt);
00254 
00255           ttgt = tree.insert_node(gtgt->get_info());
00256           GT::map_nodes(gtgt, ttgt);
00257         }
00258 
00259       typename GT::Arc * tarc = tree.insert_arc(tsrc, ttgt, garc->get_info());
00260       GT::map_arcs(garc, tarc);
00261       ARC_BITS(garc).set_bit(Min, true);
00262     }
00263 
00264   return true; // no hay ciclos negativos
00265 }
00266 
00267     template <class GT> inline static 
00268 void put_in_queue(DynListQueue<typename GT::Node*> & q, typename GT::Node * p)
00269 {
00270   q.put(p);
00271   NODE_BITS(p).set_bit(Breadth_First, true); 
00272 }
00273 
00274     template <class GT> inline static 
00275 typename GT::Node * get_from_queue(DynListQueue<typename GT::Node*> & q)
00276 {
00277   typename GT::Node * p = q.get();
00278   NODE_BITS(p).set_bit(Breadth_First, false);
00279 
00280   return p;
00281 }
00282 
00283     template <class GT> inline static
00284 bool is_in_queue(typename GT::Node * p)
00285 {
00286   return IS_NODE_VISITED(p, Breadth_First);
00287 }
00288 
00366     template <class GT, class Distance, class Compare, class Plus> inline
00367 bool q_bellman_ford_min_spanning_tree(GT &                g,
00368                                       typename GT::Node * start_node, 
00369                                       GT &                tree)
00370 {
00371   if (not g.is_digraph())
00372     throw std::domain_error("Bellman-Ford algorithm only operates on digraphs");
00373   tree.clear_graph(); // limpiar árbol abarcador destino 
00374   DynArray<typename GT::Node*> pred;
00375   DynArray<typename GT::Arc*> arcs;
00376   {
00377     typename GT::Node_Iterator it(g);
00378 
00379     for (int i = 0; it.has_current(); ++i, it.next())
00380       {
00381         typename GT::Node * p = it.get_current_node();
00382 
00383         pred[i] = NULL; 
00384         arcs[i] = NULL;
00385 
00386         g.reset_bit(p, Aleph::Min); // colocar bit en cero
00387 
00388             // apartar memoria para cookie (índice y acumulado en distancia)
00389         Bellman_Ford_Node_Info <GT, Distance> * ptr = 
00390           new Bellman_Ford_Node_Info <GT, Distance>;
00391 
00392         NODE_BITS(p).set_bit(Min, false); 
00393         NODE_BITS(p).set_bit(Breadth_First, false); 
00394         NODE_COOKIE(p) = ptr;
00395 
00396             // inicializar campos del cookie
00397         ptr->idx  = i;
00398         ptr->acum = Distance::Max_Distance;
00399     }
00400   }
00401   ACU(start_node) = Distance::Zero_Distance;
00402   g.reset_bit_arcs(Min); 
00403   DynListQueue<typename GT::Node*> q;
00404   put_in_queue <GT> (q, start_node);
00405   for (int i = 0, n = (g.get_num_nodes() - 1)*g.get_num_arcs(); 
00406        (not q.is_empty()) and i < n; // cola no vacía y no más de V.E arcos
00407        /* nothing */)
00408     {
00409       typename GT::Node * src = get_from_queue <GT> (q);
00410 
00411           // recorrer y relajar arcos del nodo src
00412       for (typename GT::Node_Arc_Iterator it(src); 
00413            it.has_current() and i < n; // haya arco y no más de V.E arcos
00414            it.next(), ++i) // avanza a siguiente arco de nodo y cuenta arco
00415         {
00416           typename GT::Arc * arc = it.get_current_arc();
00417 
00418           typename GT::Node * tgt = it.get_tgt_node();
00419 
00420           const typename Distance::Distance_Type & acum_src = ACU(src);
00421 
00422           const typename Distance::Distance_Type & w = Distance () (arc);
00423 
00424           const typename Distance::Distance_Type sum_src = Plus () (acum_src, w);
00425 
00426           typename Distance::Distance_Type & acum_tgt = ACU(tgt);
00427 
00428               // relajar arco
00429           if (Compare () (sum_src, acum_tgt)) // acum_src < acum_tgt 
00430             {
00431               const int & idx = IDX(tgt);
00432 
00433               pred[idx] = src;
00434               arcs[idx] = arc;
00435               acum_tgt  = sum_src;
00436 
00437               if (not is_in_queue <GT> (tgt))
00438                 put_in_queue <GT> (q, tgt);
00439             }
00440         }
00441     }
00442   bool ret_val = true;
00443 
00444       // recorrer todos los arcos en búsqueda de un ciclo negativo
00445   for (typename GT::Arc_Iterator it(g); it.has_current(); it.next())
00446     {
00447       typename GT::Arc * arc = it.get_current_arc();
00448 
00449       typename GT::Node * src = g.get_src_node(arc);
00450       typename GT::Node * tgt = g.get_tgt_node(arc);
00451 
00452       const typename Distance::Distance_Type & dist     = Distance () (arc);
00453       const typename Distance::Distance_Type & acum_src = ACU(src);
00454       const typename Distance::Distance_Type & acum_tgt = ACU(tgt);
00455       const typename Distance::Distance_Type sum        = Plus ()(acum_src, dist);
00456 
00457       if (Compare() (sum, acum_tgt)) // ¿lograría modificarse tgt?
00458         {
00459           ret_val = false; // se detectó un ciclo negativo
00460           break;
00461         }
00462     }
00463   if (not ret_val) // ¿hay ciclos negativos?
00464     {    // liberar memoria de los cookies de los nodos
00465       for (typename GT::Node_Iterator it(g); it.has_current(); it.next())
00466         delete NI(it.get_current_node());
00467 
00468       return false;
00469     }
00470   for (int i = 0; i < g.get_num_nodes(); ++i)
00471     {
00472       typename GT::Arc * garc = arcs[i];
00473 
00474       if (garc == NULL)
00475         continue;
00476 
00477       typename GT::Node * gsrc = g.get_src_node(garc);
00478       typename GT::Node * tsrc = NULL;
00479       if (IS_NODE_VISITED(gsrc, Min))
00480         tsrc = static_cast<typename GT::Node*>(NODE_COOKIE(gsrc));
00481       else
00482         {
00483           NODE_BITS(gsrc).set_bit(Min, true); // marcar bit
00484 
00485           delete NI(gsrc);
00486 
00487           tsrc = tree.insert_node(gsrc->get_info());
00488           GT::map_nodes(gsrc, tsrc);
00489         }
00490 
00491       typename GT::Node * gtgt = g.get_tgt_node(garc);
00492       typename GT::Node * ttgt = NULL;
00493       if (IS_NODE_VISITED(gtgt, Min))
00494         ttgt = static_cast<typename GT::Node*>(NODE_COOKIE(gtgt));
00495       else
00496         {
00497           NODE_BITS(gtgt).set_bit(Min, true); // marcar bit
00498 
00499           delete NI(gtgt);
00500 
00501           ttgt = tree.insert_node(gtgt->get_info());
00502           GT::map_nodes(gtgt, ttgt);
00503         }
00504 
00505       typename GT::Arc * tarc = tree.insert_arc(tsrc, ttgt, garc->get_info());
00506       GT::map_arcs(garc, tarc);
00507       ARC_BITS(garc).set_bit(Min, true);
00508     }
00509 
00510   return true; // no hay ciclos negativos
00511 }
00512     template <class GT, class Distance> inline
00513 bool bellman_ford_min_spanning_tree(GT &                g,
00514                                     typename GT::Node * start_node, 
00515                                     GT &                tree)
00516 {
00517   return bellman_ford_min_spanning_tree
00518     <GT, Distance, Aleph::less<typename Distance::Distance_Type>,
00519      Aleph::plus<typename Distance::Distance_Type> > (g, start_node, tree);
00520 }
00521 
00522     template <class GT, class Distance> inline
00523 bool q_bellman_ford_min_spanning_tree(GT &                g,
00524                                       typename GT::Node * start_node, 
00525                                       GT &                tree)
00526 {
00527   return q_bellman_ford_min_spanning_tree
00528     <GT, Distance, Aleph::less<typename Distance::Distance_Type>,
00529      Aleph::plus<typename Distance::Distance_Type> > (g, start_node, tree);
00530 }
00531 
00532 # undef NI
00533 # undef IDX
00534 # undef ACU
00535 } // end namespace Aleph
00536 
00537 # endif // BELLMAN_FORD_H
00538 

Leandro R. León