1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2026-01-18 00:22:03 +00:00
Files
hyperrogue/rogueviz/dhrg/embedder.cpp
2025-12-11 10:16:19 +01:00

327 lines
8.3 KiB
C++

// local search
namespace dhrg {
int newmoves = 0;
int iterations = 0;
int distlimit;
void dispnewmoves() {
if(newmoves == 0) printf(".");
else if(newmoves < 10) printf("%c", '0'+newmoves);
else printf("%c", 'a' + newmoves/10);
newmoves = 0;
}
vector<char> tomove;
bool smartmove = false;
bool dorestart = false;
int lastmoves;
int movearound() {
indenter_finish im("movearound");
int N = isize(rogueviz::vdata);
int total = 0;
if(smartmove) for(bool b: tomove) if(b) total++;
if(total == 0) {
tomove.resize(0), tomove.resize(N, true);
}
int moves = 0;
ld llo = loglik_chosen();
// int im = 0;
{progressbar pb(N, "tomove: " + its(total) + " (last: " + its(lastmoves) + ")");
for(int i=0; i<N; i++) {
if(!tomove[i]) { pb++; continue; }
tomove[i] = false;
// if(i && i % 100 == 0) dispnewmoves();
mycell *mc = vertices[i];
tallyedgesof(i, -1, mc);
add_to_set(mc, -1, 0);
add_to_tally(mc, -1, 0);
// im += size(rogueviz::vdata[i].edges);
mycell *mc2[FULL_EDGE];
ld llo2[FULL_EDGE];
int bestd = -1;
ld bestllo = llo;
auto nei = allneighbors(mc);
for(int d=0; d<isize(nei); d++) {
mc2[d] = nei[d];
if(mc2[d]->lev >= distlimit) continue;
tallyedgesof(i, 1, mc2[d]);
add_to_tally(mc2[d], 1, 0);
if(lc_type == 'C')
add_to_set(mc2[d], 1, 0);
llo2[d] = loglik_chosen();
if(lc_type == 'C')
add_to_set(mc2[d], -1, 0);
if(llo2[d] > bestllo) bestd = d, bestllo = llo2[d];
add_to_tally(mc2[d], -1, 0);
tallyedgesof(i, -1, mc2[d]);
}
if(bestd >= 0) {
moves++; newmoves++;
vertices[i] = mc = mc2[bestd];
llo = llo2[bestd];
tomove[i] = true;
for(auto p: rogueviz::vdata[i].edges) {
int j = p.second->i ^ p.second->j ^ i;
tomove[j] = true;
}
}
tallyedgesof(i, 1, mc);
add_to_tally(mc, 1, 0);
add_to_set(mc, 1, 0);
pb++;
}}
// dispnewmoves();
println(hlog, " moves = ", moves);
return lastmoves = moves;
}
int move_restart() {
indenter_finish im("move_restart");
ld llo = loglik_chosen();
array<array<int, 128>, 2> distances_map;
for(int a=0; a<2; a++) for(int b=0; b<128; b++) distances_map[a][b] = 0;
int moves = 0;
// int im = 0;
int N = isize(rogueviz::vdata);
{progressbar pb(N, "move_restart");
for(int i=0; i<N; i++) {
// if(i && i % 100 == 0) dispnewmoves();
mycell *mc = vertices[i];
tallyedgesof(i, -1, mc);
add_to_set(mc, -1, 0);
add_to_tally(mc, -1, 0);
auto getllo = [&] (mycell *m) {
tallyedgesof(i, 1, m);
add_to_tally(m, 1, 0);
if(lc_type == 'C')
add_to_set(m, 1, 0);
ld res = loglik_chosen();
if(lc_type == 'C')
add_to_set(m, -1, 0);
add_to_tally(m, -1, 0);
tallyedgesof(i, -1, m);
return res;
};
mycell* whereto = mroot;
ld bestllo = getllo(whereto);
bool changed = true;
while(changed) {
changed = false;
mycell *mc2 = whereto;
auto nei2 = allneighbors(whereto);
for(mycell *mcn: nei2) {
ld newllo = getllo(mcn);
if(newllo > bestllo)
bestllo = newllo, mc2 = mcn, changed = true;
}
if(changed) whereto = mc2;
}
bool better = bestllo > llo;
distances_map[better][quickdist(whereto, mc)]++;
if(better) {
llo = bestllo;
vertices[i] = mc = whereto;
moves++;
}
tallyedgesof(i, 1, mc);
add_to_tally(mc, 1, 0);
add_to_set(mc, 1, 0);
pb++;
}}
// dispnewmoves();
println(hlog, " moves = ", moves);
print(hlog, " stats:");
for(int a=0; a<2; a++) for(int b=0; b<128; b++) {
int d = distances_map[a][b];
if(d) print(hlog, hr::format(" %d/%d:%d", a,b, d));
}
println(hlog, "\n");
return lastmoves = moves;
}
// 7: 12694350 3847975716
// 6: 39472959 11969080911
void verifycs() {
long long edgecs = 0, totalcs = 0;
for(int u=0; u<MAXDIST; u++)
edgecs += edgetally[u] * u*u,
totalcs += tally[u] * u*u;
println(hlog, "edgecs=", hr::format("%lld", edgecs), " totalcs=", hr::format("%lld", totalcs));
}
void preparegraph() {
indenter_finish im("preparegraph");
using namespace rogueviz;
M = 0;
int N = isize(rogueviz::vdata);
vertices.resize(N);
if(1) {
progressbar pb(N, "Finding all");
for(int i=0; i<N; i++) {
M += isize(vdata[i].edges);
pb++;
}
M /= 2;
}
memoryInfo();
counttallies();
memoryInfo();
verifycs();
if(1) {
indenter_finish im("optimizing parameters");
ld factor = 1/log(cgi.expansion->get_growth());
current_logistic.setRT(factor * rogueviz::embeddings::cont_logistic.R, factor * rogueviz::embeddings::cont_logistic.T);
saved_logistic = current_logistic;
// for(int u=0; u<MAXDIST; u++) iprintf("%d/%lld\n", edgetally[u], tally[u]);
fix_logistic_parameters(current_logistic, loglik_logistic, "logistic", 1e-6);
writestats();
fflush(stdout);
}
iterations = 0;
distlimit = 0;
for(int j=0; j<BOXSIZE; j++)
if(getsegment(mroot,mroot,0)->qty[j])
distlimit = min(j+2, BOXSIZE-1);
println(hlog, "Using distlimit = ", distlimit);
}
struct dhrg_embedding : public rogueviz::embeddings::tiled_embedding {
pair<cell*, hyperpoint> as_location(int id) override {
return { vertices[id]->ascell(), C0 };
}
ld distance(int i, int j) override {
return quickdist(vertices[i], vertices[j]);
}
ld zero_distance(int i) override {
return vertices[i]->lev;
}
void save(fhstream& f) override {
int N = isize(rogueviz::vdata);
for(int i=0; i<N; i++) {
string p = get_path(vertices[i]);
if(p == "") p = "X";
println(f, rogueviz::vdata[i].name.c_str(), " ", p.c_str());
}
}
virtual string name() override { return "DHRG"; }
};
void graph_from_rv() {
using namespace rogueviz;
memoryInfo();
if(true) {
int N = isize(rogueviz::vdata);
vertices.resize(N);
progressbar pb(N, "Translating to cells");
for(int i=0; i<N; i++) {
hyperpoint T0 = rogueviz::embeddings::current->as_hyperpoint(i);
#if BUILD_ON_HR
cell *c = currentmap->gamestart();
virtualRebase2(vdata[i].m->base, T0, true);
vertices[i] = find_mycell(vdata[i].m->base);
#else
vertices[i] = find_mycell_by_path(computePath(T0));
#endif
vdata[i].m->at = Id;
pb++;
// printf("%s %s\n", vdata[i].name.c_str(), computePath(vdata[i].m->base).c_str());
}
}
recycle_compute_map();
preparegraph();
rogueviz::embeddings::enable_embedding(std::make_shared<dhrg_embedding>());
}
bool iteration() {
iterations++;
indenter_finish im("Iteration #" + its(iterations));
int m = movearound();
if(!m && dorestart) m = move_restart();
if(!m) return false;
fix_logistic_parameters(current_logistic, loglik_logistic, "logistic", 1e-6);
writestats();
fflush(stdout);
return true;
}
void embedder_loop(int max) {
indenter_finish im("embedder_loop");
ld lastopt = loglik_chosen();
while(max-- && iteration()) {
ld curopt = loglik_chosen();
println(hlog, "current = %", curopt);
if(curopt <= lastopt) {
println(hlog, "Not enough improvement -- breaking");
break;
}
lastopt = curopt;
}
}
void load_embedded(const string& s) {
if(s == "-") return graph_from_rv();
if(true) {
int N = isize(rogueviz::vdata);
progressbar pb(N, "reading embedding");
vertices.resize(N, NULL);
fhstream f(s, "rt");
while(true) {
string who = scan<string>(f);
if(who == "") break;
string where = scan<string>(f);
if(where == "X") where = "";
vertices[rogueviz::labeler.at(who)] = find_mycell_by_path(where);
pb++;
}
for(int i=0; i<N; i++) if(vertices[i] == NULL) {
printf("unmapped: %s\n", rogueviz::vdata[i].name.c_str());
throw hr_exception("unmapped vertex");
}
}
preparegraph();
rogueviz::embeddings::enable_embedding(std::make_shared<dhrg_embedding>());
}
}