00001 /**************************************************** 00002 * Bachelor Project: * 00003 * External Memory Minimum Spanning Trees * 00004 * by Dominik Schultes <mail@dominik-schultes.de> * 00005 * * 00006 * randomizer.h * 00007 * * 00008 * May 22, 2003 * 00009 ****************************************************/ 00010 00011 00012 #ifndef RANDOMIZER_H 00013 #define RANDOMIZER_H 00014 00018 class RandomizerLinearCongruence 00019 { 00020 public: 00026 RandomizerLinearCongruence(NodeCount noOfNodes) 00027 {determineNextPrime(noOfNodes);} 00028 00030 NodeID operator()(NodeID nodeID) const { 00031 typedef unsigned long long int bigNumber; 00032 00033 bigNumber x = nodeID; 00034 const bigNumber a = 321321; 00035 const bigNumber c = 1; 00036 bigNumber m = _prime; 00037 00038 // the linear congruential method 00039 return (a * x + c) % m; 00040 } 00041 00042 private: 00044 NodeCount _prime; 00045 00047 void determineNextPrime(NodeCount noOfNodes) { 00048 NodeCount p; 00049 for (p = noOfNodes-1; ! isPrime(p); p++); 00050 _prime = p; 00051 } 00052 00054 bool isPrime(NodeCount p) const { 00055 for (NodeCount i=2; i <= std::sqrt((double)p); i++) { 00056 if (p % i == 0) return false; 00057 } 00058 return true; 00059 } 00060 }; 00061 00062 00066 class RandomizerFeistel 00067 { 00068 public: 00074 RandomizerFeistel(NodeCount noOfNodes) { 00075 // compute the next integer >= the square root of the given number of nodes 00076 _sqRoot = (NodeID)std::sqrt((double)noOfNodes); 00077 if ((NodeCount)_sqRoot * _sqRoot < noOfNodes) _sqRoot++; 00078 // initialize the table of random numbers (used by the Feistel permutations) 00079 initRandomNumbers(); 00080 } 00081 00083 NodeID operator()(NodeID nodeID) const { 00084 // Split the given number into two parts 00085 int a = nodeID / _sqRoot; 00086 int b = nodeID % _sqRoot; 00087 00088 // Perform the Feistel permutations 00089 for (int i=0; i<_noOfIterations; i++) { 00090 int newA = b; 00091 b = a + randomNumbers[i][b]; 00092 if (b >= _sqRoot) b -= _sqRoot; // mod _sqRoot 00093 a = newA; 00094 } 00095 00096 // Recombine a and b to obtain the result 00097 return a * _sqRoot + b; 00098 } 00099 00100 private: 00102 static const int _noOfIterations = 2; 00103 00105 static const int _maxSqRoot = 0x10000; 00106 00108 NodeID _sqRoot; 00109 00111 int randomNumbers[_noOfIterations][_maxSqRoot]; 00112 00114 void initRandomNumbers() { 00115 for (int i=0; i<_noOfIterations; i++) 00116 for (int j=0; j<_maxSqRoot; j++) { 00117 // each random number is an integer in {0,...,_sqRoot-1} 00118 randomNumbers[i][j] = (int)(rand() / (double)(RAND_MAX+1.0) * _sqRoot); 00119 } 00120 } 00121 }; 00122 00123 00130 template <typename Bijection = RandomizerLinearCongruence> 00131 class Randomizer 00132 { 00133 public: 00135 Randomizer(NodeCount noOfNodes) 00136 : _noOfNodes( noOfNodes ), _bijection( noOfNodes ) 00137 {} 00138 00145 RelabeledEdge randomize(const Edge &edge) const { 00146 return RelabeledEdge(randomize(edge.source()),randomize(edge.target()), 00147 edge.weight(),edge.source(),edge.target()); 00148 } 00149 00150 private: 00152 NodeCount _noOfNodes; 00153 00155 Bijection _bijection; 00156 00158 NodeID randomize(NodeID nodeID) const { 00159 NodeID x = nodeID; 00160 00161 // The application of the underlying bijection is repeated 00162 // until the result is in the correct co-domain. 00163 do { 00164 x = _bijection( x ); 00165 } while (x >= _noOfNodes); 00166 00167 return x; 00168 } 00169 00170 }; 00171 00172 #endif // RANDOMIZER_H