]> git.sesse.net Git - nms/commitdiff
Add a small switch planning application.
authorSteinar H. Gunderson <sesse@samfundet.no>
Thu, 6 Apr 2006 20:30:20 +0000 (20:30 +0000)
committerSteinar H. Gunderson <sesse@samfundet.no>
Thu, 6 Apr 2006 20:30:20 +0000 (20:30 +0000)
planning/planning.cpp [new file with mode: 0644]

diff --git a/planning/planning.cpp b/planning/planning.cpp
new file mode 100644 (file)
index 0000000..73ea0f1
--- /dev/null
@@ -0,0 +1,233 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <vector>
+#include <map>
+#include <algorithm>
+
+#define NUM_DISTRO 5
+#define SWITCHES_PER_ROW 6
+#define TRUNCATE_METRIC 1
+#define TENPLUSTEN 250
+#define THIRTYPLUSTEN 450
+#define FIFTYPLUSTEN 650
+
+struct sw {
+       unsigned char row, num;
+
+       sw(unsigned char row, unsigned char num) : row(row), num(num) {}
+};
+int distro_placements[NUM_DISTRO] = {
+       5, 12, 19, 26, 33
+};
+unsigned horiz_cost[SWITCHES_PER_ROW] = {
+       346, 250, 154, 104, 200, 296
+};
+
+// memoization table
+struct key {
+       unsigned char sw_ind, distro_bound, distro_bound_hard;
+       unsigned char ports_left[NUM_DISTRO];
+
+       bool operator< (const key &other) const
+       {
+               if (sw_ind != other.sw_ind)
+                       return (sw_ind < other.sw_ind);
+               if (distro_bound != other.distro_bound)
+                       return (distro_bound < other.distro_bound);
+               if (distro_bound_hard != other.distro_bound_hard)
+                       return (distro_bound_hard < other.distro_bound_hard);
+               for (unsigned i = distro_bound_hard; i < NUM_DISTRO - 1; ++i)
+                       if (ports_left[i] != other.ports_left[i])
+                               return (ports_left[i] < other.ports_left[i]);
+               return (ports_left[NUM_DISTRO - 1] < other.ports_left[NUM_DISTRO - 1]);
+       }
+};
+struct value {
+       unsigned char distro;
+       unsigned cost, this_cost;
+};
+std::map<key, value> cache;
+unsigned cache_hits = 0;
+std::vector<sw> switches;
+
+unsigned distance(sw from_where, unsigned distro)
+{
+       // FIXME: calculate gaps as well
+       unsigned base_cost = 41 * abs(from_where.row - distro_placements[distro]) + horiz_cost[from_where.num];
+       
+       if ((from_where.row <= 9) == (distro_placements[distro] >= 10))
+               base_cost += 25;
+       if ((from_where.row <= 17) == (distro_placements[distro] >= 18))
+               base_cost += 25;
+       if ((from_where.row <= 25) == (distro_placements[distro] >= 26))
+               base_cost += 25;
+       if ((from_where.row <= 34) == (distro_placements[distro] >= 35))
+               base_cost += 25;
+
+#if TRUNCATE_METRIC
+       if (base_cost > 600)
+               return 1000;
+       if (base_cost > 500)
+               return FIFTYPLUSTEN;
+       if (base_cost > 400)
+               return 500;
+       if (base_cost > 300)
+               return THIRTYPLUSTEN;
+       if (base_cost > 200)
+               return 300;
+       if (base_cost > 100)
+               return TENPLUSTEN;
+       return 100;
+#else
+       return base_cost;
+//     return ((base_cost + 90) / 100) * 100;
+#endif
+}
+
+unsigned find_optimal_cost(key &k)
+{
+       unsigned best_cost = 999999990, best_this_cost = 0;
+       int best = -1;
+       unsigned char db = k.distro_bound;
+       unsigned char dbh = k.distro_bound_hard;
+       
+       if (k.sw_ind == switches.size())
+               return 0;
+       if (cache.count(k)) {
+               ++cache_hits;
+               return cache[k].cost;
+       }
+
+       bool next_changes_row = (k.sw_ind + 1U < switches.size() && switches[k.sw_ind].row != switches[k.sw_ind + 1].row);
+       
+       for (unsigned char i = dbh; i < dbh + 2 && i < NUM_DISTRO; ++i) {
+               if (k.ports_left[i] == 0)
+                       continue;
+               
+               unsigned cost = distance(switches[k.sw_ind], i);
+               
+               --(k.ports_left[i]);
+               ++(k.sw_ind);
+               
+               k.distro_bound = std::max(i, db);
+               if (next_changes_row) {
+                       k.distro_bound_hard = k.distro_bound;
+               }
+               
+               cost += find_optimal_cost(k);
+               --(k.sw_ind);
+               ++(k.ports_left[i]);
+
+               if (best == -1 || cost < best_cost) {
+                       best = i;
+                       best_cost = cost;
+                       best_this_cost = distance(switches[k.sw_ind], i);
+               }
+       }
+       k.distro_bound = db;
+       k.distro_bound_hard = dbh;
+
+       value v = { best, best_cost, best_this_cost };
+       cache[k] = v;
+
+       return best_cost;
+}
+
+int main()
+{
+       struct key start;
+#if TRUNCATE_METRIC
+       std::map<unsigned, unsigned> cable_count;
+#endif
+
+       switches.push_back(sw(1, 3));
+       switches.push_back(sw(1, 4));
+       switches.push_back(sw(1, 5));
+       switches.push_back(sw(2, 3));
+       switches.push_back(sw(2, 4));
+       switches.push_back(sw(2, 5));
+
+       for (unsigned i = 3; i < 35; ++i)
+               for (unsigned j = 0; j < SWITCHES_PER_ROW; ++j)
+                       switches.push_back(sw(i, j)); 
+       
+       switches.push_back(sw(35, 1));
+       switches.push_back(sw(35, 2));
+       switches.push_back(sw(35, 3));
+       switches.push_back(sw(35, 4));
+       
+       switches.push_back(sw(36, 1));
+       switches.push_back(sw(36, 2));
+       switches.push_back(sw(36, 3));
+       switches.push_back(sw(36, 4));
+       
+       switches.push_back(sw(37, 1));
+       switches.push_back(sw(37, 2));
+       switches.push_back(sw(37, 3));
+       switches.push_back(sw(37, 4));
+       
+       start.sw_ind = 0;
+       start.distro_bound = 0;
+       start.distro_bound_hard = 0;
+       start.ports_left[0] = 40;
+       start.ports_left[1] = 40;
+       start.ports_left[2] = 50;
+       start.ports_left[3] = 40;
+       start.ports_left[4] = 40;
+
+       printf("Finding optimal layout for %u switches\n", switches.size());
+       find_optimal_cost(start);
+       printf("%u cache nodes, %u cache hits.\n", cache.size(), cache_hits);
+
+       key k = start;
+       int last_row = 0, last_num = -1;
+       for (unsigned i = 0; i < switches.size(); ++i) {
+               value v = cache[k];
+               bool next_changes_row = (k.sw_ind + 1U < switches.size() && switches[k.sw_ind].row != switches[k.sw_ind + 1].row);
+
+               if (cache.count(k) == 0) {
+                       fprintf(stderr, "FATAL: no solutions!\n");
+                       exit(1);
+               }
+               
+               k.distro_bound = std::max(k.distro_bound, v.distro);
+               if (next_changes_row)
+                       k.distro_bound_hard = k.distro_bound;
+               
+               if (last_row != switches[k.sw_ind].row) {
+                       printf("\n");
+                       last_num = -1;
+               }
+               for (int j = last_num; j + 1 < switches[k.sw_ind].num; ++j) {
+                       printf("%11s", "");
+               }
+
+               
+               printf("\e[%um%u ", v.distro + 33, v.distro);
+#if TRUNCATE_METRIC
+               if (v.this_cost == FIFTYPLUSTEN)
+                       printf("(50+10)  ");
+               else if (v.this_cost == THIRTYPLUSTEN)
+                       printf("(30+10)  ");
+               else if (v.this_cost == TENPLUSTEN)
+                       printf("(10+10)  ");
+               else
+                       printf("(%-3u  )  ", v.this_cost / 10);
+               cable_count[v.this_cost]++;
+#else
+               printf("(%3.1f)   ", v.this_cost / 10.0);
+#endif
+                               
+               last_row = switches[k.sw_ind].row;
+               last_num = switches[k.sw_ind].num;
+                       
+               ++(k.sw_ind);
+               --k.ports_left[v.distro];
+       }
+       printf("\n");
+
+       for (std::map<unsigned,unsigned>::iterator i = cable_count.begin(); i != cable_count.end(); ++i)
+               printf("%u => %u\n", i->first, i->second);
+}