diff --git a/rogueviz/sag.cpp b/rogueviz/sag.cpp index 86c849b6..aa641ed9 100644 --- a/rogueviz/sag.cpp +++ b/rogueviz/sag.cpp @@ -7,14 +7,23 @@ // see: https://www.youtube.com/watch?v=WSyygk_3j9o (SAG roguelikes) // see: https://www.youtube.com/watch?v=HWQkDkeEUeM (SAG programming languages) +#include "dhrg/dhrg.h" +#include + namespace rogueviz { namespace sag { + int threads = 1; + + int informat; /* format ID */ + bool turn(int delta); int sagpar = 0; + int best_cost = 1000000000; + enum eSagmode { sagOff, sagHC, sagSA }; eSagmode sagmode; // 0 - off, 1 - hillclimbing, 2 - SA @@ -24,6 +33,10 @@ namespace sag { ld temperature = -4; const char *loadfname; + string auto_save; + + bool auto_visualize = true; + int vizsa_start; int vizsa_len; @@ -45,26 +58,91 @@ namespace sag { /** if i in neighbors[j], sagcells[i] is a neighbor of sagcells[j] */ vector> neighbors; + ld pdist(hyperpoint hi, hyperpoint hj); + + /** matrix for every sagcell */ + vector cell_matrix; + + /** precision of geometric distances */ + int gdist_prec; + + /** the maximum value in sagdist +1 */ + int max_sag_dist; + + vector sagedges; + vector> edges_yes, edges_no; + + int logistic_cost; /* 0 = disable, 1 = enable */ + dhrg::logistic lgsag(1, 1); + + vector loglik_tab_y, loglik_tab_n; + + int ipturn = 100; + int numiter = 0; + + int hightemp = 10; + int lowtemp = -15; + + /* for the embedding method: */ + bool embedding; + dhrg::logistic lgemb(1, 1); + vector placement; + + void optimize_sag_loglik(); + 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; j visited; + + auto visit = [&] (int id, const transmatrix& T) { + if(cell_matrix[id][0][0] != ERROR) return; + cell_matrix[id] = T; + visited.push_back(id); + }; + + visit(0, Id); + for(int i=0; itype; d++) + if(ids.count(c0->move(d))) + visit(ids[c0->move(d)], T0 * currentmap->adj(c0, d)); } + + if(gdist_prec) { + 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; j= 0) sagid[t2] = sid1; - cost += 2*change; + cost += change; } - void create_sagnode() { + void prepare_graph() { + int DN = isize(sagid); + + set> alledges; + for(auto e: sagedges) { + if(e.i == e.j) continue; + alledges.emplace(e.i, e.j); + alledges.emplace(e.j, e.i); + } + + edges_yes.clear(); edges_yes.resize(DN); + edges_no.clear(); edges_no.resize(DN); + + for(int i=0; i sagedges; - - int ipturn = 100; - int numiter = 0; - - int hightemp = 10; - int lowtemp = -15; - void dofullsa(int satime) { sagmode = sagSA; int t1 = SDL_GetTicks(); + int tl = -999999; while(true) { int t2 = SDL_GetTicks(); double d = (t2-t1) / (1000. * satime); if(d > 1) break; + temperature = hightemp - (d*(hightemp-lowtemp)); - chgs.clear(); - for(int i=0; i<50000; i++) { + for(int i=0; i<10000; i++) { numiter++; sag::saiter(); } - 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))); + if(t2 - tl > 980) { + tl = t2; + println(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))); + } - sort(chgs.begin(), chgs.end()); - int cc = chgs.size() - 1; - 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; @@ -290,7 +389,7 @@ namespace sag { (double) exp(-50 * exp(-sag::temperature)), (double) sag::cost)); - reassign(); + if(auto_visualize) reassign(); } void save_sag_solution(const string& fname) { @@ -299,39 +398,327 @@ namespace sag { fprintf(f, "%s;%d\n", vdata[i].name.c_str(), sagid[i]); fclose(f); } - - void loglik() { - int indist[30], pedge[30]; - for(int d=0; d<30; d++) indist[d] = 0, pedge[d] = 0; + + void compute_loglik_tab() { + loglik_tab_y.resize(max_sag_dist); + loglik_tab_n.resize(max_sag_dist); + for(int i=0; i indist(max_sag_dist, 0); + const int mul = 1; + int N = isize(sagid); for(int i=0; i pedge(max_sag_dist, 0); for(int i=0; i= sag_edge->visible_from) - pedge[sagdist[sagid[ei.i]][sagid[ei.j]]]++; + pedge[sagdist[sagid[ei.i]][sagid[ei.j]] * mul]++; } - for(int d=0; d<30; d++) + for(int d=0; d(f); + int id; + if(!labeler.count(lab)) { + printf("unknown vertex: %s\n", lab.c_str()); + continue; + } + else id = getid(lab); + ld alpha, r; + if(1) { + dynamicval g(geometry, gNormal); + hyperpoint h; + for(int d=0; d(f); + alpha = atan2(h); + r = hdist0(h); + println(hlog, "read ", lab, " as ", h, " which is ", tie(alpha, r)); + } + placement[id] = direct_exp(cspin(0, 2, alpha) * ctangent(0, r)); + println(hlog, "dist = ", pdist(placement[id], C0), " expected: ", r); + } + } + else if(informat == 3) { + /* BFKL */ + string ignore; + if(!scan(f, ignore, ignore, ignore, ignore, ignore, ignore, ignore, ignore)) { + printf("Error: incorrect format of the first line\n"); exit(1); + } + while(true) { + string lab = scan(f); + if(lab == "" || lab == "#ROGUEVIZ_ENDOFDATA") break; + ld r, alpha; + if(!scan(f, r, alpha)) { printf("Error: incorrect format of r/alpha\n"); exit(1); } + hyperpoint h = spin(alpha * degree) * xpush0(r); + + if(!labeler.count(lab)) { + printf("unknown vertex: %s\n", lab.c_str()); + } + else { + int id = getid(lab); + placement[id] = h; + } + } + } + else if(informat == 4) { + while(true) { + string lab = scan(f); + if(lab == "") break; + ld r, alpha; + if(!scan(f, r, alpha)) { printf("Error: incorrect format of r/alpha\n"); exit(1); } + hyperpoint h = spin(alpha) * xpush0(r); + + if(!labeler.count(lab)) { + printf("unknown vertex: %s\n", lab.c_str()); + } + else { + int id = getid(lab); + placement[id] = h; + } + } + } + else { + while(!feof(f.f)) { + string lab = scan(f); + int id; + if(!labeler.count(lab)) { + printf("unknown vertex: %s\n", lab.c_str()); + continue; + } + else id = getid(lab); + hyperpoint h; + for(int d=0; d(f); + placement[id] = h; + } + } + reassign_embedding(); + compute_loglik(); + } + void read_hubs(const string& fname) { hubval.resize(isize(vdata), -1); fhstream f(fname, "rt"); @@ -369,6 +756,30 @@ namespace sag { printf("Failed to open SAG file: %s\n", fname); throw "failed to open SAG file"; } + if(informat == 1) { + scanline(f); + set > edges; + + int all = 0, good = 0; + while(!feof(f.f)) { + string l1 = scan(f); + string l2 = scan(f); + if(l1 == "") continue; + if(l2 == "") continue; + edgeinfo ei(sag_edge); + ei.i = getid(l1); + ei.j = getid(l2); + if(ei.i > ei.j) swap(ei.i, ei.j); + all++; + if(edges.count({ei.i, ei.j})) continue; + good++; + edges.emplace(ei.i, ei.j); + ei.weight = 1; + sagedges.push_back(ei); + } + println(hlog, "N = ", isize(vdata), " edges = ", good, "/", all); + return; + } while(!feof(f.f)) { string l1, l2; while(true) { @@ -408,8 +819,33 @@ namespace sag { dialog::add_action([] { dialog::editNumber(sag::temperature, sag::lowtemp, sag::hightemp, 1, 0, XLAT("temperature"), ""); }); - dialog::addSelItem(XLAT("SAG mode"), sag::sagmodes[sag::sagmode], 'm'); + dialog::addSelItem(XLAT("SAG mode"), sag::sagmodes[sag::sagmode], 'm'); dialog::add_action([] { sag::sagmode = sag::eSagmode( (1+sag::sagmode) % 3 ); }); + + dialog::addSelItem(XLAT("min temperature"), fts(sag::lowtemp), 'i'); + dialog::add_action([] { + dialog::editNumber(sag::lowtemp, -20, 20, 1, 0, XLAT("min temperature"), ""); + }); + + dialog::addSelItem(XLAT("max temperature"), fts(sag::hightemp), 'i'); + dialog::add_action([] { + dialog::editNumber(sag::hightemp, -20, 20, 1, 0, XLAT("high temperature"), ""); + }); + + dialog::addSelItem(XLAT("automatic cycle"), fts(sag::vizsa_len), 'c'); + dialog::add_action([] { + dialog::editNumber(sag::vizsa_len, 5, 1800, 1, 0, XLAT("automatic cycle"), ""); + }); + + dialog::addBoolItem(XLAT("automatic"), sag::vizsa_start, 'a'); + dialog::add_action([] { + sag::vizsa_start = sag::vizsa_start ? 0 : SDL_GetTicks(); + sag::sagmode = sagOff; + }); + + dialog::addBoolItem_action(XLAT("auto-visualize"), sag::auto_visualize, 'b'); + + dialog::addBoolItem_action(XLAT("continuous embedding"), sag::embedding, 'e'); }); weight_label = "min weight"; @@ -444,7 +880,7 @@ namespace sag { } sagid.resize(DN); for(int i=0; i alldist; + for(int j=0; j 1 && logistic_cost == 2) { + vizsa_start = ticks; + optimize_sag_loglik(); + output_stats(); + } if(d > 1) sagmode = sagOff; else { temperature = hightemp - (d*(hightemp-lowtemp)); sagmode = sagSA; } } + if(sagmode == sagOff && embedding) { + embedding_iterate(); + } iterate(); return false; // shmup::pc[0]->rebase();