diff --git a/rogueviz/sag.cpp b/rogueviz/sag.cpp index 350c5348..86c849b6 100644 --- a/rogueviz/sag.cpp +++ b/rogueviz/sag.cpp @@ -22,100 +22,84 @@ namespace sag { const char *sagmodes[3] = {"off", "HC", "SA"}; ld temperature = -4; - const int INSNAKE = 117; - int numsnake; const char *loadfname; - #define MAXSNAKETAB 1000 - int sdist[MAXSNAKETAB][MAXSNAKETAB]; - int insnaketab = 0; + int vizsa_start; + int vizsa_len; + + /** all the SAG cells */ + vector sagcells; - vector snakecells; - vector snakefirst, snakelast; - vector snakenode; - vector snakeid; - vector lpbak; - vector wpbak; - - bool snake_enabled; + /** table of distances between SAG cells */ + vector> sagdist; - void setsnake(cellwalker& cw, int i) { - lpbak[i] = cw.at->landparam; - wpbak[i] = cw.at->wparam; - cw.at->landparam = i; cw.at->wparam = INSNAKE; - // cw.at->monst = moWormtail; cw.at->mondir = cw.spin; - snakecells[i] = cw.at; - } + /** what node is on sagcells[i] */ + vector sagnode; + + /** node i is on sagcells[sagid[i]] */ + vector sagid; + + /** sagcells[ids[c]]] == c */ + map ids; + + /** if i in neighbors[j], sagcells[i] is a neighbor of sagcells[j] */ + vector> neighbors; - void snakeswitch() { - for(int i=0; ilandparam; c->landparam = x; - x = wpbak[i]; wpbak[i] = c->wparam; c->wparam = x; - } - snake_enabled = !snake_enabled; - } - - void enable_snake() { if(!snake_enabled) snakeswitch(); } - - void disable_snake() { if(snake_enabled) snakeswitch(); } - - int snakedist(int i, int j) { - if(i < insnaketab && j < insnaketab) return sdist[i][j]; - if(closed_manifold) return celldistance(snakecells[i], snakecells[j]); - int i0 = i, i1 = i, j0 = j, j1 = j; - int cost = 0; - // intersect - while(true) { - if(j0 > i1+1) { j0 = snakefirst[j0], j1 = snakelast[j1]; cost++; } - else if(i0 > j1+1) { i0 = snakefirst[i0], i1 = snakelast[i1]; cost++; } - else if(j1+1 == i0) return cost+1; - else if(i1+1 == j0) return cost+1; - else return cost; + void compute_dists() { + int N = isize(sagcells); + + neighbors.clear(); + neighbors.resize(N); + + for(int i=0; i q; + auto visit = [&] (int j, int dist) { if(sdi[j] < N) return; sdi[j] = dist; q.push_back(j); }; + visit(i, 0); + for(int j=0; jallcells()); - numsnake = n; - snakecells.resize(numsnake); - snakefirst.resize(numsnake); - snakelast.resize(numsnake); - snakenode.resize(numsnake); - lpbak.resize(numsnake); - wpbak.resize(numsnake); - if(closed_or_bounded) { - for(int i=0; iallcells()[i], 0); - setsnake(cw, i); - } - } - else { - cellwalker cw = cwt; - setsnake(cw, 0); + + bool legacy; + + /* legacy method */ + void init_snake(int n) { + sagcells.clear(); + ids.clear(); + + auto enlist = [&] (cellwalker cw) { + ids[cw.at] = isize(sagcells); + sagcells.push_back(cw.at); + }; + + cellwalker cw = cwt; + enlist(cw); + cw += wstep; + enlist(cw); + for(int i=2; ilandparam; - while(cw.at->wparam == INSNAKE) { - snakelast[i-1] = cw.at->landparam; - cw = cw + wstep + 1 + wstep; - } - if(i == numsnake) break; - setsnake(cw, i); cw += 1; + while(ids.count(cw.at)) { + cw = cw + wstep + 1 + wstep; } + enlist(cw); cw += 1; } - int stab = min(numsnake, MAXSNAKETAB); - for(int i=0; iallcells(); + int N = isize(sagcells); + + ids.clear(); + for(int i=0; i hubval; @@ -127,27 +111,17 @@ namespace sag { for(int j=0; jweight2; + if(sagid[t2] != -1) cost += sagdist[sid][sagid[t2]] * ei->weight2; } if(!hubval.empty()) { - cell *c = snakecells[sid]; - for(int i=0; itype; i++) { - cell *c2 = c->move(i); - if(c2 && c2->wparam == INSNAKE) { - int vid2 = snakenode[c2->landparam]; - if(vid2 >= 0 && (hubval[vid] & hubval[snakenode[c2->landparam]]) == 0) - cost += hub_penalty; - } + for(auto sid2: neighbors[sid]) { + int vid2 = sagnode[sid2]; + if(vid2 >= 0 && (hubval[vid] & hubval[vid]) == 0) + cost += hub_penalty; } } - /* cell *c = snakecells[id]; - for(int i=0; itype; i++) { - cell *c2 = c->move(i); - if(c2 && c2->wparam == INSNAKE && snakenode[c2->landparam] >= 0) - cost += 100; - } */ return cost; } @@ -156,7 +130,6 @@ namespace sag { bool infullsa; double cost; - int N; vector chgs; @@ -177,91 +150,62 @@ namespace sag { } void saiter() { - aiter: - - int t1 = hrand(N); - int sid1 = snakeid[t1]; + int DN = isize(sagid); + int t1 = hrand(DN); + int sid1 = sagid[t1]; int sid2; - int s = hrand(6); - - if(s == 3) s = 2; - if(s == 4) s = 5; - - if((sagpar&1) && (s == 2 || s == 3 || s == 4)) return; - - if(s == 5) sid2 = hrand(numsnake); + int s = hrand(4)+1; + if(s == 4) sid2 = hrand(isize(sagcells)); else { - cell *c; - if(s>=2 && isize(vdata[t1].edges)) c = snakecells[snakeid[hrand(isize(vdata[t1].edges))]]; - else c = snakecells[sid1]; - - int it = s<2 ? (s+1) : s-2; - for(int ii=0; iitype); - c = c->move(d); - if(!c) goto aiter; - if(c->wparam != INSNAKE) goto aiter; - } - sid2 = c->landparam; + sid2 = sid1; + for(int ii=0; ii= 0) snakeid[t2] = -1; + sagnode[sid1] = -1; sagid[t1] = -1; + sagnode[sid2] = -1; if(t2 >= 0) sagid[t2] = -1; double change = costat(t1,sid2) + costat(t2,sid1) - costat(t1,sid1) - costat(t2,sid2); - - snakenode[sid1] = t1; snakeid[t1] = sid1; - snakenode[sid2] = t2; if(t2 >= 0) snakeid[t2] = sid2; - if(change < 0) chgs.push_back(-change); - + sagnode[sid1] = t1; sagid[t1] = sid1; + sagnode[sid2] = t2; if(t2 >= 0) sagid[t2] = sid2; + if(change > 0 && (sagmode == sagHC || !chance(exp(-change * exp(-temperature))))) return; - snakenode[sid1] = t2; snakenode[sid2] = t1; - snakeid[t1] = sid2; if(t2 >= 0) snakeid[t2] = sid1; - if(vdata[t1].m) vdata[t1].m->base = snakecells[sid2]; - if(t2 >= 0 && vdata[t2].m) vdata[t2].m->base = snakecells[sid1]; + sagnode[sid1] = t2; sagnode[sid2] = t1; + sagid[t1] = sid2; if(t2 >= 0) sagid[t2] = sid1; cost += 2*change; - - if(t1 >= 0) forgetedges(t1); - if(t2 >= 0) forgetedges(t2); } - void organize() { - for(int i=0; i freenodes; - for(int i=0; ibase = sagcells[sag::sagid[i]]; + forgetedges(i); + } + shmup::fixStorage(); + } + + void load_sag_solution(const string& fname) { printf("Loading the sag from: %s\n", fname.c_str()); FILE *sf = fopen(fname.c_str(), "rt"); if(!sf) { printf("Failed to open file.\n"); exit(1); } + int SN = isize(sagcells); if(sf) while(true) { string lab; while(true) { @@ -273,33 +217,24 @@ namespace sag { } int sid = -1; int err = fscanf(sf, "%d", &sid); - if(sid < 0 || sid >= numsnake || err < 1) sid = -1; + if(sid < 0 || sid >= SN || err < 1) sid = -1; if(!labeler.count(lab)) { printf("unknown vertex: %s\n", lab.c_str()); } else { int id = getid(lab); - snakeid[id] = sid; + sagid[id] = sid; } } afterload: if(sf) fclose(sf); - organize(); - for(int i=0; ibase = snakecells[sag::snakeid[i]]; - forgetedges(i); - } - - shmup::fixStorage(); + create_sagnode(); + reassign(); } vector sagedges; - /* bool totcmp(int i, int j) { - return totwei[i] > totwei[j]; - } */ - int ipturn = 100; int numiter = 0; @@ -308,7 +243,6 @@ namespace sag { void dofullsa(int satime) { sagmode = sagSA; - enable_snake(); int t1 = SDL_GetTicks(); while(true) { @@ -321,48 +255,48 @@ namespace sag { numiter++; sag::saiter(); } - DEBB(DF_LOG, (format("it %8d temp %6.4f [1/e at %13.6f] cost = %f ", + + print(hlog, format("it %8d temp %6.4f [1/e at %13.6f] cost = %f ", numiter, double(sag::temperature), (double) exp(sag::temperature), - double(sag::cost)))); + double(sag::cost))); sort(chgs.begin(), chgs.end()); int cc = chgs.size() - 1; - DEBB(DF_LOG, (format("%9.4f .. %9.4f .. %9.4f .. %9.4f .. %9.4f\n", - double(chgs[0]), double(chgs[cc/4]), double(chgs[cc/2]), double(chgs[cc*3/4]), double(chgs[cc])))); - fflush(stdout); + println(hlog, format("%9.4f .. %9.4f .. %9.4f .. %9.4f .. %9.4f", + double(chgs[0]), double(chgs[cc/4]), double(chgs[cc/2]), double(chgs[cc*3/4]), double(chgs[cc]))); } temperature = -5; - disable_snake(); sagmode = sagOff; + reassign(); } void iterate() { if(!sagmode) return; int t1 = SDL_GetTicks(); - enable_snake(); for(int i=0; i 200) ipturn /= 2; else ipturn = ipturn * 100 / t; - DEBB(DF_LOG, ("it %8d temp %6.4f [2:%8.6f,10:%8.6f,50:%8.6f] cost = %f\n", + print(hlog, format("it %8d temp %6.4f [2:%8.6f,10:%8.6f,50:%8.6f] cost = %f\n", numiter, double(sag::temperature), (double) exp(-2 * exp(-sag::temperature)), (double) exp(-10 * exp(-sag::temperature)), (double) exp(-50 * exp(-sag::temperature)), (double) sag::cost)); + + reassign(); } - void savesnake(const string& fname) { + void save_sag_solution(const string& fname) { FILE *f = fopen(fname.c_str(), "wt"); - for(int i=0; i= sag_edge->visible_from) - pedge[snakedist(snakeid[ei.i], snakeid[ei.j])]++; + pedge[sagdist[sagid[ei.i]][sagid[ei.j]]]++; } for(int d=0; d<30; d++) @@ -434,8 +365,10 @@ namespace sag { maxweight = 0; sag_edge = add_edgetype("SAG edge"); fhstream f(fname, "rt"); - if(!f.f) { printf("Failed to open SAG file: %s\n", fname); exit(1); } - // while(fgetc(f) != 10 && fgetc(f) != 13 && !feof(f)) ; + if(!f.f) { + printf("Failed to open SAG file: %s\n", fname); + throw "failed to open SAG file"; + } while(!feof(f.f)) { string l1, l2; while(true) { @@ -485,53 +418,39 @@ namespace sag { if(hub_filename != "") read_hubs(hub_filename); - N = isize(vdata); - // totwei.resize(N); - // for(int i=0; i= maxwei[ei.i] / 5 || ei.weight >= maxwei[ei.j] / 5); ei.weight2 = pow((double) ei.weight, (double) edgepower) * edgemul; - // LANG:: pow(ei.weight, .4) / 50; - // ei.weight2 = 0; int w = ei.weight; while(w) { w >>= 1; ei.weight2++; } - /* if(totwei[ei.i] <= 0 || totwei[ei.j] <= 0) { - printf("BAD TOTWEI\n"); - exit(1); - } - ei.weight2 = 3 * ( - sqrt(ei.weight * 1. / totwei[ei.i]) * log(totwei[ei.i]) * log(totwei[ei.i]) + - sqrt(ei.weight * 1. / totwei[ei.j]) * log(totwei[ei.j]) * log(totwei[ei.j])); */ - // printf("%f\n", ei.weight2); addedge0(ei.i, ei.j, &ei); } - initSnake(N*2); - printf("numsnake = %d\n", numsnake); - if(numsnake < N) { - printf("Error: snake does not fit\n"); + if(legacy) + init_snake(2 * DN); + else + init_sag_cells(); + + compute_dists(); + + int SN = isize(sagcells); + if(SN < DN) { + println(hlog, "SN = ", SN, " DN = ", DN); + throw hr_exception("not enough cells for SAG"); exit(1); } - snakeid.resize(N); - for(int i=0; i - else if(argis("-fullsa")) { + else if(argis("-sagfull")) { shift(); sag::dofullsa(argi()); } + else if(argis("-sagviz")) { + sag::vizsa_start = SDL_GetTicks(); + shift(); sag::vizsa_len = argi(); + } // (5) save the positioning - else if(argis("-gsave")) { - PHASE(3); shift(); sag::savesnake(args()); + else if(argis("-sagsave")) { + PHASE(3); shift(); sag::save_sag_solution(args()); } // (6) output loglikelihood - else if(argis("-lik")) { + else if(argis("-sagloglik")) { sag::loglik(); } + else if(argis("-sagmode")) { + shift(); + sagmode = (eSagmode) argi(); + if(sagmode == sagSA) { + shift(); temperature = argf(); + } + } else return 1; #endif return 0; } bool turn(int delta) { + if(vizsa_start) { + auto t = ticks; + double d = (t-vizsa_start) / (1000. * vizsa_len); + if(d > 1) sagmode = sagOff; + else { + temperature = hightemp - (d*(hightemp-lowtemp)); + sagmode = sagSA; + } + } + iterate(); return false; // shmup::pc[0]->rebase(); } @@ -634,9 +574,10 @@ int ah = addHook(hooks_args, 100, readArgs) drawthemap(); gmatrix0 = gmatrix; + slide_backup(rogueviz::sag::legacy, true); rogueviz::sag::read(RVPATH "roguelikes/edges.csv"); rogueviz::readcolor(RVPATH "roguelikes/color.csv"); - rogueviz::sag::loadsnake(RVPATH "roguelikes/" + cname()); + rogueviz::sag::load_sag_solution(RVPATH "roguelikes/" + cname()); }) } ); @@ -654,9 +595,10 @@ int ah = addHook(hooks_args, 100, readArgs) drawthemap(); gmatrix0 = gmatrix; + slide_backup(rogueviz::sag::legacy, true); rogueviz::sag::read(RVPATH "lang/edges.csv"); rogueviz::readcolor(RVPATH "lang/color.csv"); - rogueviz::sag::loadsnake(RVPATH "lang/" + cname()); + rogueviz::sag::load_sag_solution(RVPATH "lang/" + cname()); if(euclid) rogueviz::legend.clear(); }) }); @@ -675,9 +617,10 @@ int ah = addHook(hooks_args, 100, readArgs) drawthemap(); gmatrix0 = gmatrix; + slide_backup(rogueviz::sag::legacy, true); rogueviz::sag::read(RVPATH "boardgames/edges.csv"); rogueviz::readcolor(RVPATH "boardgames/color.csv"); - rogueviz::sag::loadsnake(RVPATH "boardgames/" + cname()); + rogueviz::sag::load_sag_solution(RVPATH "boardgames/" + cname()); }) });