mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-30 20:10:35 +00:00
ced3bbcad4
C++20 introduces `std::format` and we `using namespace std`, so some of these would be ambiguous in C++20.
341 lines
8.3 KiB
C++
341 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 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 = {0};
|
|
int moves = 0;
|
|
// int im = 0;
|
|
|
|
{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;
|
|
|
|
print(hlog, "edgecs=", hr::format("%lld", edgecs), " totalcs=", hr::format("%lld", totalcs));
|
|
}
|
|
|
|
void preparegraph() {
|
|
indenter_finish im("preparegraph");
|
|
using namespace rogueviz;
|
|
M = 0;
|
|
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();
|
|
|
|
cont_logistic.setRT(graph_R, graph_T);
|
|
|
|
counttallies();
|
|
|
|
memoryInfo();
|
|
|
|
verifycs();
|
|
|
|
if(1) {
|
|
indenter_finish im("optimizing parameters");
|
|
ld factor = 1/log(cgi.expansion->get_growth());
|
|
current_logistic.setRT(factor * graph_R, factor * graph_T);
|
|
saved_logistic = current_logistic;
|
|
|
|
// for(int u=0; u<MAXDIST; u++) iprintf("%d/%Ld\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);
|
|
}
|
|
|
|
void read_graph_full(const string& fname) {
|
|
using namespace rogueviz;
|
|
|
|
memoryInfo();
|
|
|
|
if(true) {
|
|
indenter_finish im("Read graph");
|
|
|
|
// N = isize(vdata);
|
|
|
|
read_graph(fname, false, false, false);
|
|
vertices.resize(N);
|
|
progressbar pb(N, "Translating to cells");
|
|
|
|
for(int i=0; i<N; i++) {
|
|
#if BUILD_ON_HR
|
|
cell *c = currentmap->gamestart();
|
|
hyperpoint T0 = vdata[i].m->at * C0;
|
|
virtualRebase2(vdata[i].m->base, T0, true);
|
|
vertices[i] = find_mycell(vdata[i].m->base);
|
|
#else
|
|
vertices[i] = find_mycell_by_path(computePath(vdata[i].m->at));
|
|
#endif
|
|
vdata[i].m->at = Id;
|
|
pb++;
|
|
// printf("%s\n", computePath(vdata[i].m->base).c_str());
|
|
}
|
|
}
|
|
|
|
recycle_compute_map();
|
|
preparegraph();
|
|
}
|
|
|
|
void graph_from_rv() {
|
|
using namespace rogueviz;
|
|
|
|
memoryInfo();
|
|
|
|
vertices.resize(N);
|
|
progressbar pb(N, "converting RogueViz to DHRG");
|
|
|
|
for(int i=0; i<N; i++) {
|
|
#if BUILD_ON_HR
|
|
vertices[i] = find_mycell(vdata[i].m->base);
|
|
#else
|
|
auto path1 = computePath(vdata[i].m->base);
|
|
vertices[i] = find_mycell_by_path(path1);
|
|
#endif
|
|
vdata[i].m->at = Id;
|
|
pb++;
|
|
}
|
|
|
|
preparegraph();
|
|
}
|
|
|
|
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 save_embedding(const string s) {
|
|
FILE *f = fopen(s.c_str(), "wt");
|
|
for(int i=0; i<N; i++) {
|
|
string p = get_path(vertices[i]);
|
|
if(p == "") p = "X";
|
|
fprintf(f, "%s %s\n", rogueviz::vdata[i].name.c_str(), p.c_str());
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
void load_embedded(const string s) {
|
|
if(true) {
|
|
read_graph(s, false, false, false);
|
|
indenter_finish im("Read graph");
|
|
}
|
|
|
|
string t = rogueviz::fname + "-dhrg.txt";
|
|
|
|
if(true) {
|
|
progressbar pb(N, "reading embedding");
|
|
vertices.resize(N, NULL);
|
|
|
|
map<string, int> ids;
|
|
for(int i=0; i<N; i++) ids[rogueviz::vdata[i].name] = i;
|
|
|
|
FILE *f = fopen(t.c_str(), "rt");
|
|
while(true) {
|
|
char who[500], where[500];
|
|
who[0] = 0;
|
|
fscanf(f, "%s%s", who, where);
|
|
if(who[0] == 0) break;
|
|
if(!ids.count(who)) printf("unknown vertex: %s\n", who);
|
|
string wh = where;
|
|
if(wh == "X") wh = "";
|
|
vertices[ids[who]] = find_mycell_by_path(wh);
|
|
pb++;
|
|
}
|
|
fclose(f);
|
|
|
|
for(int i=0; i<N; i++) if(vertices[i] == NULL) {
|
|
printf("unmapped: %s\n", rogueviz::vdata[i].name.c_str());
|
|
exit(1);
|
|
}
|
|
}
|
|
preparegraph();
|
|
}
|
|
|
|
}
|