Prim.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 PRIM_H
00045 # define PRIM_H
00046 
00047 # include <tpl_graph.H>
00048 # include <tpl_graph_utils.H>
00049 # include <archeap.H>
00050 
00051 using namespace Aleph;
00052 
00053 namespace Aleph {
00054 
00055 template <class GT> struct Prim_Info
00056 {
00057   typename GT::Node * tree_node; // imagen del nodo en el árbol abarcador
00058   void *              heap_node; // puntero dentro del heap exclusivo
00059 
00060   Prim_Info() : tree_node(NULL), heap_node(NULL) { /* empty */ } 
00061 };
00062 # define PRIMINFO(p) static_cast<Prim_Info<GT>*>(NODE_COOKIE(p))
00063 # define TREENODE(p) (PRIMINFO(p)->tree_node)
00064 # define HEAPNODE(p) (PRIMINFO(p)->heap_node)
00065       template <class GT, class Distance, class Compare>
00066 struct Prim_Heap_Info
00067 {
00068   typedef typename ArcHeap<GT, Distance, Compare, Prim_Heap_Info>::Node Node;
00069   
00070   Node *& operator () (typename GT::Node * p)
00071   {
00072     return (Node*&) HEAPNODE(p);
00073   }
00074 };
00075     template <class GT>
00076 struct Init_Prim_Info
00077 {
00078   void operator () (GT & g, typename GT::Node * p)
00079   {
00080     g.reset_bit(p, Aleph::Prim); 
00081     NODE_COOKIE(p) = new Prim_Info<GT>;
00082   }
00083 };
00084     template <class GT>
00085 struct Uninit_Prim_Info
00086 {
00087   void operator () (GT &, typename GT::Node * p)
00088   {
00089     Prim_Info<GT> * aux = PRIMINFO(p);
00090     GT::map_nodes(p, TREENODE(p));
00091     delete aux;
00092   }
00093 };
00145     template <class GT, class Distance, class Compare> inline 
00146 void prim_min_spanning_tree(GT & g, GT & tree)
00147 {
00148 
00149   if (g.is_digraph())
00150     throw std::domain_error("g is a digraph");
00151 
00152   if (not test_connectivity(g))
00153     throw std::invalid_argument("Input graph is not conected");
00154   tree.clear_graph(); 
00155 
00156   g.template operate_on_nodes <Init_Prim_Info <GT> > ();
00157   typedef Prim_Heap_Info<GT, Distance, Compare> Acc_Heap;
00158   ArcHeap<GT, Distance, Compare, Acc_Heap> heap;
00159       // inicializar la raíz con el primer nodo del grafo 
00160   typename GT::Node * first = g.get_first_node();
00161   NODE_BITS(first).set_bit(Aleph::Prim, true); // marcarlo visitado
00162 
00163       // guardar imagen de nodo en el árbol abarcador
00164   TREENODE(first) = tree.insert_node(first->get_info());
00165 
00166       // meter en heap arcos iniciales del primer nodo
00167   for (typename GT::Node_Arc_Iterator it(first); it.has_current(); it.next())
00168     {
00169       typename GT::Arc * arc = it.get_current_arc();
00170       ARC_BITS(arc).set_bit(Aleph::Prim, true);
00171       heap.put_arc(arc, it.get_tgt_node());
00172     }
00173   while (tree.get_num_nodes() < g.get_num_nodes()) // mientras tree no abarque a g
00174     {     // obtenga siguiente menor arco 
00175       typename GT::Arc * min_arc = heap.get_min_arc();
00176 
00177       typename GT::Node * src = g.get_src_node(min_arc);
00178       typename GT::Node * tgt = g.get_tgt_node(min_arc);
00179 
00180       if (IS_NODE_VISITED(src, Aleph::Prim) and 
00181           IS_NODE_VISITED(tgt, Aleph::Prim))
00182         continue; // Este arco cerraría un ciclo en el árbol 
00183 
00184       typename GT::Node * tgt_node = // seleccione nodo no marcado
00185         IS_NODE_VISITED(src, Aleph::Prim) ? tgt : src;
00186 
00187           // inserte en árbol, guarde node de árbol y marque nodo como visitado
00188       TREENODE(tgt_node) = tree.insert_node(tgt_node->get_info());
00189       NODE_BITS(tgt_node).set_bit(Aleph::Prim, true);
00190 
00191           // insertar en heap arcos no visitados de tgt_node
00192       for (typename GT::Node_Arc_Iterator it(tgt_node); it.has_current(); it.next())
00193         {
00194           typename GT::Arc * arc = it.get_current_arc();
00195 
00196           if (IS_ARC_VISITED(arc, Aleph::Prim))
00197             continue;
00198 
00199           ARC_BITS(arc).set_bit(Aleph::Prim, true); // marcar arco
00200 
00201           typename GT::Node * tgt = it.get_tgt_node();
00202 
00203           if (IS_NODE_VISITED(tgt, Aleph::Dijkstra)) 
00204             continue; // nodo visitado ==> causará ciclo ==> no se requiere
00205                       // insertar en heap  
00206 
00207           heap.put_arc(arc, tgt);
00208         }
00209             // inserte nuevo arco en tree
00210       typename GT::Arc * tree_arc = 
00211         tree.insert_arc(TREENODE(src), TREENODE(tgt), min_arc->get_info());
00212 
00213       GT::map_arcs(min_arc, tree_arc); // mapear arcos
00214     }
00215   g.template operate_on_nodes <Uninit_Prim_Info <GT> > ();      
00216 }
00217 
00218     template <class GT, class Distance> inline 
00219 void prim_min_spanning_tree(GT & g, GT & tree)
00220 {
00221   prim_min_spanning_tree
00222     <GT, Distance, Aleph::less<typename Distance::Distance_Type> > (g, tree);
00223 }
00224 
00225 
00226 # undef HEAPNODE
00227 # undef TREENODE
00228 # undef PRIMINFO
00229 } // end namespace Aleph
00230 
00231 # endif // PRIM_H
00232 

Leandro R. León