dijkstra.hxx

Go to the documentation of this file.
00001 // Copyright (C) 2003-2006 Laboratoire de Recherche en Informatique
00002 
00003 // This file is part of Qolyester.
00004 
00005 // Qolyester is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 // Qolyester is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018 // Boston, MA  02110-1301, USA.
00019 
00020 #ifndef QOLYESTER_DAEMON_ALG_DIJKSTRA_HXX
00021 # define QOLYESTER_DAEMON_ALG_DIJKSTRA_HXX 1
00022 
00023 # include <ext/hash_map>
00024 
00025 # include "gra/graph.hh"
00026 # include "net/ipaddress.hh"
00027 # include "utl/comparator.hh"
00028 # include "utl/log.hh"
00029 
00030 # include "dijkstra.hh"
00031 
00032 namespace olsr {
00033 
00034   extern debug_ostream_t        debug;
00035   extern gra::AdjGraph          path_net;
00036 
00037   namespace alg {
00038     // Declarations of the two dijkstra data structures.  nextmap_t
00039     // maps node addresses into addresses of the next node towards the
00040     // first node.  hopsmap_t maps node addresses into the actual
00041     // number of hops.  Infinite number of hops is reprensented by the
00042     // absence of a node in the hopsmap.
00043     typedef std::hash_map<address_t, unsigned>  weightmap_t;
00044     typedef std::hash_map<address_t, address_t> nextmap_t;
00045     typedef std::hash_map<address_t, unsigned>  hopsmap_t;
00046 
00047     // Sorting comparator of the nodes remaining to be processed.
00048     struct sort_less {
00049       // We need to pass a reference to the instance of hopsmap_t to
00050       // use.
00051       sort_less(const hopsmap_t& hm,
00052                 const weightmap_t& wm)
00053         : _hm(hm),
00054           _wm(wm)
00055       {}
00056 
00057       bool operator()(const gra::AdjNode* a, const gra::AdjNode* b) const {
00058         // Get the number of hops towards each of the nodes.
00059         weightmap_t::const_iterator     wa = _wm.find(a->endpoint());
00060         weightmap_t::const_iterator     wb = _wm.find(b->endpoint());
00061 
00062         hopsmap_t::const_iterator     ha = _hm.find(a->endpoint());
00063         hopsmap_t::const_iterator     hb = _hm.find(b->endpoint());
00064 
00065         // If both of the nodes are at infinite number of hops, order
00066         // simply by node address.  If only one of the two is at
00067         // infinity, make it greater than the other.
00068         if (wb == _wm.end())
00069           if (wa == _wm.end())
00070             return a->endpoint() < b->endpoint();
00071           else
00072             return true;
00073 
00074         if (wa == _wm.end())
00075           return false;
00076 
00077         if (wa->second > wb->second)
00078           return true;
00079         else if (wa->second < wb->second)
00080           return false;
00081 
00082         if (hb == _hm.end())
00083           if (ha == _hm.end())
00084             return a->endpoint() < b->endpoint();
00085           else
00086             return true;
00087 
00088         if (ha == _hm.end())
00089           return false;
00090 
00091         // From now on, we know that both nodes are not at infinity.
00092 
00093         // Order the nodes primary by number of hops.
00094         if (ha->second < hb->second)
00095           return true;
00096         else if (hb->second < ha->second)
00097           return false;
00098 
00099         // Order the nodes secondary by weight.
00100         if (b->weight() < a->weight())
00101           return true;
00102         else if (a->weight() < b->weight())
00103           return false;
00104 
00105         // Last, order the nodes by address.
00106         return a->endpoint() < b->endpoint();
00107       }
00108     private:
00109       const hopsmap_t&          _hm;
00110       const weightmap_t&        _wm;
00111     };
00112 
00113     // Declaration of the node hash set type.
00114     typedef std::hash_set<const gra::AdjNode*,
00115                           gra::hash_AdjNode,
00116                           utl::pequal_to<gra::AdjNode> >        npset_t;
00117 
00118     // Declaration of the remaining node set type.
00119     typedef std::set<const gra::AdjNode*, sort_less>    sortremaining_t;
00120 
00121     // The Dijkstra algorithm.  The first argument is a reference to
00122     // the route set to be filled and the second argument is the set
00123     // of source nodes addresses.
00124     void        dijkstra(rrouteset_t& routes, lmap_t& sources_map) {
00125       nextmap_t         next_map;
00126       hopsmap_t         hops_map;
00127       weightmap_t       weight_map;
00128 
00129       debug << path_net << std::endl;
00130 
00131       npset_t   rem;
00132 
00133       // Insert all the nodes of the graph into the remaining set.
00134       for (gra::nodeset_t::const_iterator n = path_net.nodes().begin();
00135            n != path_net.nodes().end(); ++n)
00136         rem.insert(&*n);
00137 
00138       debug << "dijkstra {\n";
00139 
00140       // Initialize the hops and next map, by inserting the source
00141       // nodes.
00142       debug << "  sources {";
00143       for (lmap_t::const_iterator s = sources_map.begin();
00144            s != sources_map.end(); ++s) {
00145         pathnet_t::nset_t::const_iterator       n =
00146           path_net.nodes().find(gra::AdjNode::make_key(s->first));
00147 
00148         if (n == path_net.nodes().end())
00149           n = path_net.nodes().
00150             find(gra::AdjNode::make_key(s->second.second->main_addr()));
00151 
00152         assert(n != path_net.nodes().end());
00153 
00154         debug << ' ' << s->first;
00155         next_map[s->first] = s->first;
00156         hops_map[s->first] = 0;
00157         weight_map[s->first] = n->weight();
00158       }
00159       debug << " }\n";
00160 
00161       // Loop while there are remaining nodes to be reached.
00162       while (!hops_map.empty() && !rem.empty()) {
00163 
00164         // Populate the sorted remaining set.
00165         sortremaining_t srem(rem.begin(), rem.end(),
00166                              sort_less(hops_map, weight_map));
00167 
00168         debug << "  round {\n";
00169         for (sortremaining_t::const_iterator i = srem.begin();
00170              i != srem.end(); ++i) {
00171           debug << "    " << (*i)->endpoint() << ' ';
00172           nextmap_t::const_iterator n = next_map.find((*i)->endpoint());
00173           hopsmap_t::const_iterator h = hops_map.find((*i)->endpoint());
00174           weightmap_t::const_iterator w = weight_map.find((*i)->endpoint());
00175           if (n == next_map.end())
00176             debug << "_ ";
00177           else
00178             debug << n->second << ' ';
00179           if (h == hops_map.end())
00180             debug << "_ ";
00181           else
00182             debug << h->second << ' ';
00183           if (w == weight_map.end())
00184             debug << "_\n";
00185           else
00186             debug << w->second << '\n';
00187         }
00188         debug << "  }" << std::endl;
00189 
00190         // The first node (in iteration order) in the sorted remaining
00191         // set is the node that is to be added next to the reached
00192         // set.
00193         const gra::AdjNode&     closest = **srem.begin();
00194 
00195         // Remove the node from the remaining set.
00196         rem.erase(&closest);
00197         srem.erase(&closest);
00198 
00199         // Get new hop count and next node address for relaxation.
00200 
00201         hopsmap_t::iterator     hops = hops_map.find(closest.endpoint());
00202         nextmap_t::iterator     next = next_map.find(closest.endpoint());
00203         weightmap_t::iterator   weight = weight_map.find(closest.endpoint());
00204 
00205         if (hops == hops_map.end() ||
00206             next == next_map.end() ||
00207             weight == weight_map.end())
00208           break; // We are now considering an unreachable node, stop here.
00209 
00210         unsigned        next_hops = hops->second + 1;
00211 
00212         // Remove the node from the hops map.
00213         hops_map.erase(hops);
00214         weight_map.erase(weight);
00215 
00216         if (closest.weight() == 0)
00217           continue;
00218 
00219         // The relaxation /per se/
00220 
00221         // Iterate on the node set.
00222         for (npset_t::const_iterator n = rem.begin(); n != rem.end(); ++n) {
00223           // Consider only the nodes that are adjacent to the current
00224           // node.
00225           pathnet_t::aset_t::const_iterator     a =
00226             path_net.arcs().find(gra::AdjInfo::make_key(closest.endpoint(),
00227                                                         (*n)->endpoint(),
00228                                                         topo));
00229           // The following case is put to allow the use of 2-hop
00230           // neighbors information on the condition that the 1-hop
00231           // neighbor is symmetric, i.e. it is one of the source
00232           // nodes.
00233           if (a == path_net.arcs().end() &&
00234               sources_map.find(closest.endpoint()) != sources_map.end())
00235             a = path_net.arcs().find(gra::AdjInfo::make_key(closest.endpoint(),
00236                                                             (*n)->endpoint(),
00237                                                             twohop));
00238 
00239           if (a != path_net.arcs().end()) {
00240             // Get the hops map entry and update it, along with the
00241             // next map entry.
00242             unsigned                    next_weight = MAX(weight->second,
00243                                                           (*n)->weight());
00244             //        weight->second + a->weight();
00245             hopsmap_t::iterator         h = hops_map.find((*n)->endpoint());
00246             weightmap_t::iterator       w = weight_map.find((*n)->endpoint());
00247             if (((w == weight_map.end() || w->second <= next_weight) &&
00248                  (h == hops_map.end() || h->second > next_hops)) ||
00249                 ((w == weight_map.end() || w->second < next_weight) &&
00250                  (h == hops_map.end() || h->second >= next_hops))) {
00251               weight_map[(*n)->endpoint()] = next_weight;
00252               hops_map[(*n)->endpoint()] = next_hops;
00253               next_map[(*n)->endpoint()] = next->second;
00254             }
00255           }
00256         }
00257       }
00258 
00259       // Remove the source nodes from the next map.
00260       for (lmap_t::const_iterator s = sources_map.begin();
00261            s != sources_map.end(); ++s)
00262         next_map.erase(s->first);
00263 
00264       // Build the route set based on the next map.
00265       for (nextmap_t::const_iterator i = next_map.begin();
00266            i != next_map.end(); ++i) {
00267         debug << "  route { " << i->first << " : " << i->second << " }\n";
00268 
00269         assert(sources_map.find(i->second) != sources_map.end());
00270         routes.insert(net::RemoteRoute(i->first, ADDRESS_SIZE * 8,
00271                                        sources_map[i->second].first));
00272       }
00273 
00274       debug << '}' << std::endl;;
00275     }
00276 
00277   } // namespace alg
00278 
00279 } // namespace olsr
00280 
00281 #endif // !QOLYESTER_DAEMON_ALG_DIJKSTRA_HXX

Generated on Mon Sep 10 17:02:11 2007 for Qolyester daemon by  doxygen 1.5.1