1 module tests.drift; 2 3 import tests.utils; 4 import vivaldi; 5 6 @("drift") 7 unittest { 8 import std.algorithm : map, max, min, sum; 9 import std.format; 10 import std.math; 11 import std.random; 12 13 // Stable seed for random unitvectors. 14 rndGen().seed(1); 15 16 alias N = Node!(Coordinate!2, 20); 17 18 immutable double dist = 0.5; 19 immutable size_t n = 4; 20 21 N[n] nodes = new N[n]; 22 23 nodes[0].coordinate.vector = [ 0.0, 0.0 ]; 24 nodes[1].coordinate.vector = [ 0.0, dist ]; 25 nodes[2].coordinate.vector = [ dist, dist ]; 26 nodes[3].coordinate.vector = [ dist, 0.0 ]; 27 28 auto matrix = matrix!n; 29 30 // The nodes are laid out like this so the distances are all 31 // equal, except for the diagonal: 32 // 33 // (1) <- dist -> (2) 34 // 35 // | <- dist | 36 // | | 37 // | dist -> | 38 // 39 // (0) <- dist -> (3) 40 for (size_t i = 0; i < n; i++) { 41 for (size_t j = i + 1; j < n; j++) { 42 double rtt = dist; 43 44 if (i % 2 == 0 && j % 2 == 0) { 45 rtt *= SQRT2; 46 } 47 48 matrix[i][j] = rtt; 49 matrix[j][i] = rtt; 50 } 51 } 52 53 double centerError() { 54 auto mini = nodes[0].coordinate; 55 auto maxi = nodes[0].coordinate; 56 57 for (size_t i = 1; i < n; i++) { 58 auto coord = nodes[i].coordinate; 59 60 foreach (j, v; coord.vector) { 61 mini.vector[j] = min(mini.vector[j], v); 62 maxi.vector[j] = max(maxi.vector[j], v); 63 } 64 } 65 66 auto mid = new double[2]; 67 68 for (size_t i = 0; i < 2; i++) { 69 mid[i] = mini.vector[i] + (maxi.vector[i] - mini.vector[i]) / 2; 70 } 71 72 return sqrt(sum(mid.map!(a => a * a))); 73 } 74 75 simulate!(N, 3, n)(nodes, matrix, 1000); 76 double baseline = centerError(); 77 78 simulate!(N, 3, n)(nodes, matrix, 10000); 79 80 double err = centerError(); 81 assert(err <= 0.81 * baseline, format("err=%s baseline=%s", err, baseline)); 82 }