OverSim
CoordBasedRouting.cc
Go to the documentation of this file.
1 //
2 // Copyright (C) 2008 Institut fuer Telematik, Universitaet Karlsruhe (TH)
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18 
26 #include <fstream>
27 #include <string>
28 #include <cassert>
29 #include <algorithm>
30 
31 #include <omnetpp.h>
32 
33 #include <GlobalNodeListAccess.h>
34 #include <PeerInfo.h>
35 
36 #include "CoordBasedRouting.h"
37 
38 
40 
41 const std::string CoordBasedRouting::NOPREFIX = "NOPREFIX";
42 
44 {
45  areaCoordinateSource = par("areaCoordinateSource");
46  cbrStartAtDigit = par("CBRstartAtDigit");
47  cbrStopAtDigit = par("CBRstopAtDigit");
48  cbrChangeIdLater = par("CBRchangeIdLater");
49  cbrChangeIdStart = par("CBRchangeIdStart");
50  cbrChangeIdStop = par("CBRchangeIdStop");
52 
53  gap = new AP;
54 
55  // XML file found?
56  if (std::string(areaCoordinateSource) == "") {
57  EV << "[CoordBasedRouting::initialize()]\n No CBR area file found."
58  << " Using dCBR." << endl;
59  return;
60  }
61 
62  std::ifstream check_for_xml_file(areaCoordinateSource);
63  if (!check_for_xml_file) {
64  check_for_xml_file.close();
65  //TODO
66  throw cRuntimeError("CBR area file not found!");
67  return;
68  }
69  else {
70  EV << "[CoordBasedRouting::initialize()]\n CBR area file '"
71  << areaCoordinateSource << "' loaded." << endl;
72  check_for_xml_file.close();
73  }
74 
75  // XML file found, let's parse it
77 }
78 
79 
81 {
82  gap->clear();
83 }
84 
85 
86 void CoordBasedRouting::parseSource(const char* areaCoordinateSource)
87 {
88  cXMLElement* rootElement = ev.getXMLDocument(areaCoordinateSource);
89 
90  xmlDimensions = atoi(rootElement->getAttribute("dimensions"));
91 
92  for (cXMLElement *area = rootElement->getFirstChildWithTag("area"); area;
93  area = area->getNextSiblingWithTag("area") ) {
94  CBRArea tmpArea(xmlDimensions);
95  for (cXMLElement *areavals = area->getFirstChild(); areavals;
96  areavals = areavals->getNextSibling() ) {
97  std::string tagname = std::string(areavals->getTagName());
98  if (tagname == "min") {
99  uint8_t currentdim = atoi(areavals->getAttribute("dimension"));
100  double value = atof(areavals->getNodeValue());
101  tmpArea.min[currentdim] = value;
102  }
103 
104  else if (tagname == "max") {
105  uint8_t currentdim = atoi(areavals->getAttribute("dimension"));
106  double value = atof(areavals->getNodeValue());
107  tmpArea.max[currentdim] = value;
108  }
109 
110  else if (tagname == "prefix") {
111  tmpArea.prefix = areavals->getNodeValue();
112  }
113  }
114  gap->push_back(tmpArea);
115  }
116 
117  EV << "[CoordBasedRouting::parseSource()]" << endl;
118  EV << " " << gap->size() << " prefix areas detected." << endl;
119 }
120 
121 
123  const std::string& prefix,
124  const Coords& bottoms,
125  const Coords& tops,
126  uint8_t depth,
127  AP* cap)
128 {
129  // check
130  if (nodes.size() < 2 || prefix.length() >= maxPrefix) {
131  //std::cout << "nodes: " << nodes.size() << ", prefix.length(): " << prefix.length() << std::endl;
132  CBRArea temp(bottoms, tops, prefix);
133  //std::cout << temp << std::endl;
134  cap->push_back(temp);
135  return;
136  }
137 
138  // sort
139  uint8_t splitDim = depth % ccdDim;
140  sort(nodes.begin(), nodes.end(), leqDim(splitDim));
141 
142  // new vectors for two halfs
143  uint32_t newSize = nodes.size() / 2;
144  CD lnodes(newSize), rnodes(nodes.size() - newSize);
145 
146  // split
147  CD::iterator halfIt = nodes.begin();
148  for (uint32_t i = 0; i < newSize; ++i, ++halfIt);
149  assert(halfIt != nodes.end());
150  double splitCoord = (nodes[newSize - 1][splitDim] + nodes[newSize][splitDim]) / 2;
151 
152  std::copy(nodes.begin(), halfIt, lnodes.begin());
153  std::copy(halfIt, nodes.end(), rnodes.begin());
154 
155  // set area borders
156  Coords newBottoms, newTops;
157  newBottoms = bottoms;
158  newTops = tops;
159  newBottoms[splitDim] = newTops[splitDim] = splitCoord;
160 
161  // recursive calls
162  splitNodes(lnodes, prefix + '0', bottoms, newTops, ++depth, cap);
163  splitNodes(rnodes, prefix + '1', newBottoms, tops, depth, cap);
164 
165 
166  /*
167 
168  def splitByNodes(returnval)
169  #returnval = 0: return lower half node set
170  #returnval = 1: return upper half node set
171  #returnval = 2: return split coordinate
172  num = @nodes.length
173  half = (num / 2).floor
174  splitcoord = (@nodes[half-1][@thisdim] + @nodes[half][@thisdim]) / 2
175  case returnval
176  when 0
177  return @nodes[0..half-1]
178  when 1
179  return @nodes[half..num-1]
180  when 2
181  return splitcoord
182  end
183  end
184  */
185 }
186 
187 
188 const AP* CoordBasedRouting::calculateCapFromCcd(const CD& ccd, uint8_t bpd)
189 {
190  if (ccd.size() == 0) return NULL;
191 
192  AP* cap = new AP();
193  maxPrefix = bpd * cbrStopAtDigit; //TODO
194 
195  ccdDim = ccd[0].size();
196 
197  Coords bottoms(ccdDim, -1500), tops(ccdDim, 1500);
198  std::string prefix;
199 
200  CD nodes = ccd;
201  splitNodes(nodes, prefix, bottoms, tops, 0, cap);
202 
203  return cap;
204 
205 
206  /*
207 
208  def split()
209  # split unless no more nodes left or maximum prefix length is reached
210  unless @nodes == nil || @depth >= MAXPREFIX
211  lnodes = splitByNodes(0)
212  unodes = splitByNodes(1)
213  splitcoord = splitByNodes(2);
214 
215  lnodes = nil if lnodes.length <= MINNODES
216  unodes = nil if unodes.length <= MINNODES
217 
218  newbottoms = []
219  @bottoms.each do |bottom|
220  newbottoms << bottom
221  end
222  newbottoms[@thisdim] = splitcoord
223 
224  newtops = []
225  @tops.each do |top|
226  newtops << top
227  end
228  newtops[@thisdim] = splitcoord
229 
230  addChild(lnodes, @prefix+"0", @bottoms, newtops);
231  addChild(unodes, @prefix+"1", newbottoms, @tops);
232 
233  @children.each do |child|
234  child.split
235  end
236  end
237  end
238  */
239 }
240 
241 
243  uint8_t bpd, uint8_t length,
244  const AP* cap) const
245 {
246  std::string prefix = getPrefix(coords, cap);
247 
248  // if no prefix is returned, something is seriously wrong with the Area Source XML
249  if (prefix == NOPREFIX) {
250  std::stringstream ss;
251  ss << "[CoordBasedRouting::getNodeId()]: No prefix for given coords (";
252  for (uint8_t i = 0; i < coords.size(); ++i) {
253  ss << coords[i];
254  if (i != (coords.size() - 1)) {
255  ss << ", ";
256  }
257  }
258  ss << ") found. Check your area source file!";
259 
260  EV << ss.str() << endl;
261  //std::cout << ss.str() << std::endl;
262  return OverlayKey::random();
263  }
264  std::string idString;
265 
266  // ID string:
267  // |- endPos
268  // 00000000000000011010101010000000000000
269  // |_startLength_||_prefix_||_endLength_|
270  // |__ .. beforeEnd .. __|
271  // |___ .... length .... ___|
272  //
273  // startLength and endLength bits are set to 0 at first, then
274  // randomized
275  // Prefix will be cut off if stop digit is exceeded
276 
277  uint8_t startLength = (bpd * cbrStartAtDigit < length) ?
278  (bpd * cbrStartAtDigit) : length;
279  uint8_t beforeEnd = (startLength + prefix.length() < length) ?
280  (startLength + prefix.length()) : length;
281  uint8_t endPos = (bpd * cbrStopAtDigit < beforeEnd) ?
282  (bpd * cbrStopAtDigit) : beforeEnd;
283  uint8_t endLength = length - endPos;
284 
285  // Fill startLength bits with zeros
286  for (uint8_t i = 0; i < startLength; i++)
287  idString += "0";
288 
289  // Now add prefix and cut it off if stop digit and/or key length is exceeded
290  idString += prefix;
291  if (endPos < idString.length())
292  idString.erase(endPos);
293  if (length < idString.length())
294  idString.erase(length);
295 
296  // fill endLength bits with zeros, thus key length is reached
297  for (uint8_t i = 0; i < endLength; i++)
298  idString += "0";
299 
300  OverlayKey nodeId(idString, 2);
301 
302  // randomize non-prefix (zero filled) parts
303  if (startLength > 0)
304  nodeId = nodeId.randomPrefix(length - startLength);
305  if (endLength > 0)
306  nodeId = nodeId.randomSuffix(endLength);
307 
308  EV << "[CoordBasedRouting::getNodeId()]\n"
309  <<" calculated id: " << nodeId << endl;
310  return nodeId;
311 }
312 
313 std::string CoordBasedRouting::getPrefix(const Coords& coords,
314  const AP* cap) const
315 {
316  //for (uint8_t i = 0; i < coords.size(); ++i) {
317  // std::cout << coords[i] << ", ";
318  //}
319  //std::cout << std::endl;
320 
321  bool areaFound = false;
322  uint32_t iter = 0;
323 
324  // TODO dimension in dCBR
325  /*
326  // Return no prefix if coords dimensions don't match area file dimensions
327  if (!checkDimensions(coords.size())) {
328  //std::cout << "dim" << std::endl;
329  return NOPREFIX;
330  }
331  */
332 
333  const AP* ap = ((cap != NULL) ? cap : gap);
334  //assert(ap && (ap->size() > 0));
335 
336  /*
337  for (uint i = 0; i < ap->size(); ++i) {
338  for (uint j = 0; i < ap->at(i).min.size(); ++j) {
339  std::cout << ap->at(i).min[j] << " - " << ap->at(i).max[j] << std::endl;
340  }
341  }
342  */
343 
344  while (!areaFound && iter < ap->size()) {
345  //std::cout << (*ap)[iter].min.size() << std::endl;
346  CBRArea thisArea = (*ap)[iter];
347 
348  // assume we're in the correct area unless any dimension tells us otherwise
349  areaFound = true;
350  for (uint8_t thisdim = 0; thisdim < coords.size(); thisdim++) {
351  if (coords[thisdim] < thisArea.min[thisdim] ||
352  coords[thisdim] > thisArea.max[thisdim]) {
353  areaFound = false;
354  break;
355  }
356  }
357 
358  // no borders are broken in any dimension -> we're in the correct area,
359  // return corresponding prefix
360  if (areaFound) {
361  EV << "[CoordBasedRouting::getPrefix()]\n"
362  <<" calculated prefix: " << thisArea.prefix << endl;
363  //std::cout << "[CoordBasedRouting::getPrefix()]\n"
364  // <<" calculated prefix: " << thisArea.prefix << std::endl;
365  return thisArea.prefix;
366  }
367  iter++;
368  }
369 
370  // no corresponding prefix found, XML file broken?
371  EV << "[CoordBasedRouting::getPrefix()]\n"
372  << " No corresponding prefix found, check your area source file!"
373  << endl;
374 
375  return NOPREFIX;
376 }
377 
379  const Coords& coords,
380  uint8_t bpd,
381  const AP* cap) const
382 {
383  assert(!destKey.isUnspecified());
384  uint32_t iter = 0;
385  const AP* ap = ((cap != NULL) ? cap : gap);
386  assert(ap);
387 
388  while (iter < ap->size()) {
389  CBRArea thisArea = (*ap)[iter];
390 
391  // Take CBR Start/Stop Digit into account
392  uint8_t startbit = bpd * cbrStartAtDigit;
393  uint8_t length = (bpd * cbrStopAtDigit - bpd * cbrStartAtDigit <
394  (uint8_t)thisArea.prefix.length() - bpd * cbrStartAtDigit)
395  ? (bpd * cbrStopAtDigit - bpd * cbrStartAtDigit)
396  : (thisArea.prefix.length() - bpd * cbrStartAtDigit);
397  if (destKey.toString(2).substr(startbit, length) ==
398  thisArea.prefix.substr(startbit, length)) {
399  // Get euclidian distance of area center to given coords
400  Coords areaCenterCoords;
401  areaCenterCoords.resize(getXmlDimensions());
402  double sumofsquares = 0;
403  for (uint8_t dim = 0; dim < getXmlDimensions(); dim++) {
404  areaCenterCoords[dim] =
405  (thisArea.min[dim] + thisArea.max[dim]) / 2;
406  sumofsquares += pow((coords[dim] - areaCenterCoords[dim]), 2);
407  }
408  return sqrt(sumofsquares);
409  }
410  iter++;
411  }
412  // while loop finished -> no area with needed prefix found
413  // (this shouldn't happen!)
414  throw cRuntimeError("[CoordBasedRouting::"
415  "getEuclidianDistanceByKeyAndCoords]: "
416  "No prefix for search key found!");
417  return -1;
418 }
419 
420 
421 bool CoordBasedRouting::checkDimensions(uint8_t dims) const
422 {
423  if (dims == xmlDimensions) {
424  return true;
425  } else {
426  EV << "[CoordBasedRouting::checkDimensions()]" << endl;
427  EV << " ERROR: Given coordinate dimensions do not match dimensions "
428  "in the used area source file. Mapping results will be wrong."
429  << endl;
430  return false;
431  }
432 }
433 
434 
438 CBRArea::CBRArea(uint8_t dim)
439 : min(dim, 0.0), max(dim, 0.0)
440 {
441  //min.reserve(dim);
442  //max.reserve(dim);
443 }
444 
445 std::ostream& operator<<(std::ostream& os, const CBRArea& area)
446 {
447  for (uint i = 0; i < area.min.size(); ++i) {
448  os << "|" << area.min[i] << " - " << area.max[i] << "|";
449  }
450  os << " -> \"" << area.prefix << "\"";
451 
452  return os;
453 }