1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2026-03-16 18:19:43 +00:00

rogueviz:: moved some parts from dhrg to embeddings

This commit is contained in:
Zeno Rogue
2025-12-04 23:21:46 +01:00
parent 2e71f31a3f
commit aed65e5bc0
15 changed files with 428 additions and 513 deletions

View File

@@ -1,27 +1,16 @@
// -noscr -slides DHRG rv_latex=1 -slide-textoff -title c000
#include "rogueviz.h"
#include "embeddings/embeddings.h"
#include "dhrg/dhrg.h"
#if CAP_RVSLIDES
namespace dhrg {
void graphv(std::string s);
extern double graph_R;
extern int N;
extern int iterations;
void unsnap();
bool dhrg_animate(int sym, int uni);
void rvcoords();
void clear();
void prepare_pairs();
std::vector<int> path(int src);
int get_actual(int src);
void prepare_goal(int goal);
}
namespace hr {
using namespace rogueviz::pres;
using namespace rogueviz::embeddings;
shared_ptr<embedding> dhrg_embedding;
int find_vertex(string name) {
int id = 0;
@@ -50,12 +39,12 @@ int me, them;
void greedy_test() {
me = find_vertex("Eryk_Kopczynski");
auto me2 = find_vertex("Erich_Grädel");
dhrg::prepare_pairs();
dhrg::rvcoords();
prepare_pairs();
reenable_embedding();
them = find_vertex(dhrg::iterations ? "Florian_Willich" : "Stéphane_Chrétien");
for(int goal=0; goal<dhrg::N; goal++) {
dhrg::prepare_goal(goal);
auto p = dhrg::path(me2);
for(int goal=0; goal<isize(rogueviz::vdata); goal++) {
prepare_goal(goal);
auto p = path(me2);
if(p.back() == goal) {
println(hlog, "actual = ", dhrg::get_actual(me), " p = ", p, " ~ ", rogueviz::vdata[p.back()].name);
}
@@ -69,7 +58,10 @@ void greedy_test() {
void launch_sea() {
enable_canvas_backup(&ccolor::plain);
start_game();
dhrg::graphv("rogueviz/dhrg-data/sea-ppl");
read_edgelist("rogueviz/dhrg-data/sea-ppl-links.txt");
read_polar("rogueviz/dhrg-data/sea-ppl-coordinates.txt");
dhrg_embedding = current;
dhrg::graph_from_rv();
resetview();
}
@@ -192,7 +184,7 @@ void graph_visuals(presmode mode) {
void swap_snap() {
snapped = !snapped;
if(snapped) { for(auto& v: rogueviz::vdata) v.be(v.m->base, Id); }
if(!snapped) dhrg::unsnap();
if(!snapped) enable_embedding(dhrg_embedding);
}
void dhrg_hooks() {

View File

@@ -323,6 +323,7 @@ bool neq(betweenness_type a, betweenness_type b) {
}
void compute_betweenness(bool verify) {
auto N = isize(rogueviz::vdata);
progressbar pb(N, "compute_betweenness");
int errorcount = 0, errorcount2 = 0;
for(int i=0; i<N; i++) {
@@ -383,7 +384,6 @@ void build(mycell *c, int lev, string s) {
void build_all(int d) {
build(mroot, d, "");
N = isize(vertices);
counttallies();
}
@@ -398,7 +398,6 @@ void load_test() {
rogueviz::vdata.back().name = "PATH:" + s;
}
// build(mroot, 5, "");
N = isize(vertices);
counttallies();
// add_to_set(vertices[0], -1, 0);
}

View File

@@ -16,13 +16,11 @@ namespace rogueviz { extern string fname; }
#include "tests.cpp"
#include "betweenness.cpp"
#include "groundtruth.cpp"
#include "routing.cpp"
namespace dhrg {
int M;
vector<struct mycell*> vertices;
vector<ld> disttable0, disttable1;
void memoryInfo() {
string s = "";
@@ -48,17 +46,9 @@ void debugtally() {
println(hlog, " .. %", loglikopt());
}
void place_rogueviz_vertices() {
progressbar pb(N, "place_rogueviz_vertices");
// transmatrix In = inverse(ggmatrix(currentmap->gamestart()));
using namespace rogueviz;
for(int i=0; i<N; i++) vdata[i].be(vertices[i]->ascell(), Id);
}
int destroy;
void clear() {
coords.clear();
// destroytallies();
// todo: correct cleanup!
for(int i=0; i<MAXDIST; i++) tally[i] = 0;
@@ -90,35 +80,16 @@ int ts_coords;
int ts_vertices;
bool stored;
void graphv(string s) {
dhrg_init(); read_graph(s);
next_timestamp++;
ts_rogueviz = next_timestamp;
ts_rbase = next_timestamp;
stored = true;
}
int dhrgArgs() {
using namespace arg;
if(argis("-dhrg")) {
PHASE(3); shift(); dhrg_init(); read_graph_full(args());
PHASE(3); dhrg_init(); graph_from_rv();
next_timestamp++;
ts_rogueviz = next_timestamp;
ts_vertices = next_timestamp;
}
else if(argis("-graph")) {
PHASE(3); shift(); dhrg_init(); read_graph(args());
next_timestamp++;
ts_rogueviz = next_timestamp;
// stored = true;
}
else if(argis("-graphv")) {
PHASE(3); shift(); graphv(args());
}
else if(argis("-analyze_grid")) {
PHASE(3); shift(); dhrg_init(); do_analyze_grid(argi());
}
@@ -131,36 +102,6 @@ int dhrgArgs() {
PHASE(3); dhrg_init(); shift(); test_paths(argi());
}
else if(argis("-contll")) {
if(ts_rogueviz >= ts_rbase && ts_rogueviz >= ts_vertices && ts_rogueviz > ts_coords) {
origcoords();
build_disttable_approx();
ts_coords = ts_rogueviz;
}
else if(ts_rbase >= ts_vertices && ts_rbase > ts_coords) {
ts_coords = ts_rbase;
rvcoords();
build_disttable_approx();
}
else if(ts_vertices > ts_coords) {
ts_coords = ts_vertices;
cellcoords();
build_disttable_approx();
}
logistic cont;
cont.setRT(graph_R, graph_T);
fast_loglik_cont(cont, loglik_cont_approx, "lcont", 1, 1e-6);
// return loglik_cont();
}
else if(argis("-dhrgview")) {
if(ts_vertices > ts_rbase) {
place_rogueviz_vertices();
ts_rbase = ts_vertices;
}
mainloop(); quitmainloop = false;
}
else if(argis("-iterate")) {
if(ts_rbase > ts_vertices) {
@@ -209,10 +150,6 @@ int dhrgArgs() {
shift(); ground_truth_test(args());
}
else if(argis("-routing")) {
shift(); routing_test(args());
}
else if(argis("-esaveas")) {
shift(); save_embedding(args());
}
@@ -237,7 +174,6 @@ void store_gamedata(struct hr::gamedata* gd) {
if(true) {
for(auto& t: tally) gd->store(t);
for(auto& t: edgetally) gd->store(t);
gd->store(coords);
#ifdef BUILD_ON_HR
gd->store(mymap);
#else

View File

@@ -2,6 +2,7 @@
#define _DHRG_H_
#define DHRGVER "7.1"
#include "../rogueviz.h"
#include "../embeddings/embeddings.h"
#define LONG_BRACKETS
@@ -28,53 +29,13 @@ extern vector<ld> disttable0, disttable1;
void memoryInfo();
void cellcoords();
void origcoords();
void build_disttable();
void dhrg_init();
bool dhrg_animate(int sym, int uni);
/* implemented in loglik.cpp: */
extern int iterations;
/* for logistic regression */
struct logistic {
ld R, T;
ld yes1(ld d) { return 1/(1 + exp(d)); }
ld no1(ld d) { return 1/(1 + exp(-d)); }
ld nor(ld d) { return (d-R) / 2 / T; }
ld yes(ld d) { return yes1(nor(d)); }
ld no(ld d) { return no1(nor(d)); }
ld lyes(ld d) { d = nor(d); return d > 200 ? -d : log(yes1(d)); }
ld lno(ld d) { d = nor(d); return d < -200 ? d : log(no1(d)); }
logistic() {}
logistic(ld _R, ld _T) : R(_R), T(_T) {}
void setRT(ld _R, ld _T) { R = _R; T = _T; }
};
extern ld llcont_approx_prec;
extern vector<array<ll, 2>> disttable_approx;
using logisticfun = std::function<ld(logistic&)>;
extern logistic current_logistic;
ld loglik_cont_approx(logistic& l = current_logistic);
void fast_loglik_cont(logistic& l, const logisticfun& f, const char *name, ld start, ld eps);
/* greedy routing */
struct iddata {
ld tot, suc, routedist, bestdist;
iddata() { tot = suc = routedist = bestdist = 0; }
};
using neighborhoodfun = std::function<vector<int> (int)>;
using distfun = std::function<ld(int a, int b)>;
void prepare_pairs(int N, const neighborhoodfun& nei);
void greedy_routing(iddata& d, const distfun& distance_function);
void clear();
void graph_from_rv();
}
#endif

View File

@@ -22,6 +22,7 @@ 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) {
@@ -90,6 +91,8 @@ int move_restart() {
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++) {
@@ -165,6 +168,7 @@ void preparegraph() {
indenter_finish im("preparegraph");
using namespace rogueviz;
M = 0;
int N = isize(rogueviz::vdata);
vertices.resize(N);
if(1) {
@@ -178,8 +182,6 @@ void preparegraph() {
memoryInfo();
cont_logistic.setRT(graph_R, graph_T);
counttallies();
memoryInfo();
@@ -189,7 +191,7 @@ void preparegraph() {
if(1) {
indenter_finish im("optimizing parameters");
ld factor = 1/log(cgi.expansion->get_growth());
current_logistic.setRT(factor * graph_R, factor * graph_T);
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]);
@@ -209,17 +211,28 @@ void preparegraph() {
println(hlog, "Using distlimit = ", distlimit);
}
void read_graph_full(const string& fname) {
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 graph_from_rv() {
using namespace rogueviz;
memoryInfo();
if(true) {
indenter_finish im("Read graph");
// N = isize(vdata);
read_graph(fname);
int N = isize(rogueviz::vdata);
vertices.resize(N);
progressbar pb(N, "Translating to cells");
@@ -239,29 +252,9 @@ void read_graph_full(const string& fname) {
}
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();
rogueviz::embeddings::enable_embedding(std::make_shared<dhrg_embedding>());
}
bool iteration() {
@@ -293,6 +286,7 @@ void embedder_loop(int max) {
void save_embedding(const string s) {
FILE *f = fopen(s.c_str(), "wt");
int N = isize(rogueviz::vdata);
for(int i=0; i<N; i++) {
string p = get_path(vertices[i]);
if(p == "") p = "X";
@@ -301,22 +295,17 @@ void save_embedding(const string s) {
fclose(f);
}
void load_embedded(const string s) {
if(true) {
read_graph(s);
indenter_finish im("Read graph");
}
string t = rogueviz::fname + "-dhrg.txt";
void load_embedded(const string& s) {
if(true) {
int N = isize(rogueviz::vdata);
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");
FILE *f = fopen(s.c_str(), "rt");
while(true) {
char who[500], where[500];
who[0] = 0;
@@ -336,6 +325,7 @@ void load_embedded(const string s) {
}
}
preparegraph();
rogueviz::embeddings::enable_embedding(std::make_shared<dhrg_embedding>());
}
}

View File

@@ -9,6 +9,8 @@ bool is(char *where, const char *what) {
}
void ground_truth_test(string s) {
throw hr_exception("this test is currently not implemented to work after the structural changes");
#if 0
logistic cont;
@@ -38,8 +40,6 @@ if(1) {
origcoords();
build_disttable();
cont.setRT(graph_R, graph_T);
report("gz", loglik_cont(cont));
fix_logistic_parameters(cont, loglik_cont, "lcont", 1e-3);
report("grc", loglik_cont(cont));
@@ -51,7 +51,6 @@ if(1) {
report("gcm", loglikopt_mono());
report("gcrt", loglik_logistic());
cont.setRT(graph_R, graph_T);
report("gcz", loglik_cont(cont));
fix_logistic_parameters(cont, loglik_cont, "lcont", 1e-3);
report("gcrc", loglik_cont(cont));
@@ -65,7 +64,6 @@ if(1) {
cellcoords();
build_disttable();
cont.setRT(graph_R, graph_T);
fix_logistic_parameters(cont, loglik_cont, "lcont", 1e-3);
report("gerc", loglik_cont(cont));
@@ -81,7 +79,6 @@ if(1) {
dhrg_init(); read_graph_full("data/sime-" + s);
origcoords();
build_disttable();
cont.setRT(graph_R, graph_T);
report("ez", loglik_cont(cont));
fix_logistic_parameters(cont, loglik_cont, "lcont", 1e-3);
report("erc", loglik_cont(cont));
@@ -93,7 +90,6 @@ if(1) {
cellcoords();
build_disttable();
cont.setRT(graph_R, graph_T);
report("ecz", loglik_cont(cont));
fix_logistic_parameters(cont, loglik_cont, "lcont", 1e-3);
report("ecrc", loglik_cont(cont));
@@ -110,12 +106,12 @@ if(1) {
cellcoords();
build_disttable();
cont.setRT(graph_R, graph_T);
fix_logistic_parameters(cont, loglik_cont, "lcont", 1e-3);
report("eerc", loglik_cont(cont));
print(hlog, "HDR;", separated(";", reps), ";TIME;N;GROWTH\n");
print(hlog, "RES'", separated(";", logliks), ";", int(tim), ";", N, ";", cgi.expansion->get_growth());
#endif
}
}

View File

@@ -1,14 +1,7 @@
// log-likelihood computation
#include <thread>
#define USE_THREADS
namespace dhrg {
int threads = 32;
ld llcont_approx_prec = 10000;
// tally edges of the given vertex at the given index
int edgetally[MAXDIST];
@@ -26,6 +19,7 @@ void tallyedgesof(int i, int delta, mycell *mc) {
void counttallies() {
using namespace rogueviz;
int N = isize(rogueviz::vdata);
{
progressbar pb(N, "Tallying pairs");
@@ -53,127 +47,19 @@ void counttallies() {
}
void destroytallies() {
int N = isize(rogueviz::vdata);
progressbar pb(N, "Destroying tallies");
for(int i=0; i<N; i++) add_to_set(vertices[i], -1, 0), pb++;
for(int i=0; i<MAXDIST; i++)
tally[i] = edgetally[i] = 0;
}
// log likelihood utilities
//--------------------------
// MLE of the binomial distribution (a successes, b failures)
ld bestll(ld a, ld b) {
if(a == 0 || b == 0) return 0;
return a * log(a/(a+b)) + b * log(b/(a+b));
}
// a successes, ab total
ld bestll2(ld a, ld ab) { return bestll(a, ab-a); }
// various methods of loglikelihood computation
template<class T> void fix_logistic_parameters(logistic& l, const T& f, const char *name, ld eps) {
indenter_finish im("fix_logistic_parameters");
ld cur = f(l);
println(hlog, hr::format("%s = %20.10" PLDF " (R=%10.5" PLDF " T=%" PLDF ")", name, cur, l.R, l.T));
for(ld step=1; step>eps; step /= 2) {
while(true) { l.R += step; ld t = f(l); if(t <= cur) break; cur = t; }
l.R -= step;
while(true) { l.R -= step; ld t = f(l); if(t <= cur) break; cur = t; }
l.R += step;
while(true) { l.T += step; ld t = f(l); if(t <= cur) break; cur = t; }
l.T -= step;
while(true) { l.T -= step; ld t = f(l); if(t <= cur) break; cur = t; }
l.T += step;
println(hlog, hr::format("%s = %20.10" PLDF " (R=%10.5" PLDF " T=%10.5" PLDF ")", name, cur, l.R, l.T));
fflush(stdout);
}
}
using rogueviz::embeddings::logistic;
logistic current_logistic;
logistic saved_logistic;
logistic cont_logistic;
// --- continuous logistic loglikelihood
// --------------------------------------
vector<hyperpoint> vertexcoords;
// compute vertexcoords from the original embedding data
void origcoords() {
indenter_finish im("origcoords");
using namespace rogueviz;
vertexcoords.resize(N);
for(int i=0; i<N; i++)
vertexcoords[i] = spin(coords[i].second * degree) * xpush(coords[i].first) * C0;
}
// compute vertexcoords from the RogueViz representation
void rvcoords() {
indenter_finish im("rvcoords");
using namespace rogueviz;
vertexcoords.resize(N);
for(int i=0; i<N; i++)
vertexcoords[i] = calc_relative_matrix(rogueviz::vdata[i].m->base, currentmap->gamestart(), C0) * rogueviz::vdata[i].m->at * C0;
}
// compute vertexcoords from vertices
void cellcoords() {
indenter_finish im("cellcoords");
vertexcoords.resize(N);
for(int i=0; i<N; i++) {
vertexcoords[i] = celltopoint(vertices[i]->ascell()); // calc_relative_matrix(vertices[i]->ascell(), currentmap->gamestart(), C0) * C0;
if(isnan(vertexcoords[i][0])) println(hlog, "got NAN for i=", i, " in lev= ", vertices[i]->lev);
}
}
// needs cellcoords/rvcoords/origcoords
void build_disttable() {
indenter_finish im("build_disttable");
vector<int> tab(N, N);
disttable0.clear();
disttable1.clear();
using namespace rogueviz;
for(int i=0; i<N; i++) {
for(auto p: vdata[i].edges) {
int j = p.second->i ^ p.second->j ^ i;
if(j<i) tab[j] = i;
}
for(int j=0; j<i; j++) {
ld dist = hdist(vertexcoords[i], vertexcoords[j]);
if(dist < 0) continue;
(tab[j] == i ? disttable1:disttable0).push_back(dist);
}
}
sort(disttable0.begin(), disttable0.end());
sort(disttable1.begin(), disttable1.end());
}
// needs build_disttable
ld loglik_cont(logistic& l = current_logistic) {
ld llh = 1;
for(auto p: disttable1) llh += l.lyes(p);
for(auto p: disttable0) {
ld lp = l.lno(p);
llh += lp;
if(lp > -1e-10) break;
}
return llh;
}
// --- placement loglikelihood
@@ -181,6 +67,7 @@ ld loglik_placement() {
mycell *root = mroot;
ld placement_loglik = 0;
auto seg = getsegment(root,root,0);
int N = isize(rogueviz::vdata);
for(int j=0; j<BOXSIZE; j++) {
int qj = seg->qty[j];
if(!qj) continue;
@@ -204,7 +91,7 @@ ld loglik_logistic(logistic& l = current_logistic) {
ld loglikopt() {
ld result = 0;
for(int u=0; u<MAXDIST; u++) result += bestll2(edgetally[u], tally[u]);
for(int u=0; u<MAXDIST; u++) result += rogueviz::embeddings::bestll2(edgetally[u], tally[u]);
return result;
}
@@ -225,7 +112,7 @@ ld loglikopt_mono() {
pairs.push_back(p);
}
for(auto p: pairs)
result += bestll2(p.first, p.second);
result += rogueviz::embeddings::bestll2(p.first, p.second);
return result;
}
@@ -257,6 +144,7 @@ ld loglik_chosen() {
void writestats() {
indenter_finish im("writestats");
memoryInfo();
int N = isize(rogueviz::vdata);
println(hlog, "Vertices by distance (N = ", N, "):");
mycell *root = mroot;
for(int j=0; j<BOXSIZE; j++) {
@@ -274,7 +162,7 @@ void writestats() {
}
println(hlog, "log likelihood\n");
ld loglik_chaos = bestll2(M, N*(N-1)/2);
ld loglik_chaos = rogueviz::embeddings::bestll2(M, N*(N-1)/2);
ld loglik_opt = loglikopt();
ld loglik_mono = loglikopt_mono();
ld loglik_rt = loglik_logistic();
@@ -307,8 +195,6 @@ template<class T> auto parallelize(long long N, T action) -> decltype(action(0,0
#endif
}
vector<array<ll, 2>> disttable_approx;
ld precise_hdist(hyperpoint vi, hyperpoint vj) {
ld da = acosh(vi[2]);
ld db = acosh(vj[2]);
@@ -325,106 +211,4 @@ ld precise_hdist(hyperpoint vi, hyperpoint vj) {
return acosh(v);
}
void build_disttable_approx() {
indenter_finish im("build_disttable_approx");
array<ll, 2> zero = {0, 0};
using namespace rogueviz;
std::vector<vector<array<ll, 2>>> results(threads);
std::vector<std::thread> v;
for(int k=0; k<threads; k++)
v.emplace_back([&,k] () {
auto& dt = results[k];
vector<int> tab(N, N);
auto p = k ? nullptr : new progressbar(N/threads, "build_disttable_approx");
for(int i=k; i<N; i+=threads) {
if(p) (*p)++;
for(auto p: vdata[i].edges) {
int j = p.second->i ^ p.second->j ^ i;
if(j<i) tab[j] = i;
}
for(int j=0; j<i; j++) {
ld dist = precise_hdist(vertexcoords[i], vertexcoords[j]);
if(dist < 0) continue;
int dista = dist * llcont_approx_prec;
if(isize(dt) < dista+1)
dt.resize(dista+1, zero);
dt[dista][(tab[j] == i) ? 1 : 0]++;
}
}
if(p) delete p;
});
for(std::thread& t:v) t.join();
int mx = 0;
for(auto& r: results) mx = max(mx, isize(r));
disttable_approx.clear();
disttable_approx.resize(mx, zero);
for(auto& r: results)
for(int i=0; i<isize(r); i++)
for(int j=0; j<2; j++)
disttable_approx[i][j] += r[i][j];
}
ld loglik_cont_approx(logistic& l) {
ld llh = 0;
int N = isize(disttable_approx);
for(int i=0; i<N; i++) {
if(disttable_approx[i][0])
llh += l.lno((i+.5)/llcont_approx_prec) * disttable_approx[i][0];
if(disttable_approx[i][1])
llh += l.lyes((i+.5)/llcont_approx_prec) * disttable_approx[i][1];
}
return llh;
}
using logisticfun = std::function<ld(logistic&)>;
int max_steps = 100000;
void fast_loglik_cont(logistic& l, const logisticfun& f, const char *name, ld start, ld eps) {
if(name) println(hlog, "fix_logistic_parameters");
indenter_finish im(name);
ld cur = f(l);
if(name) println(hlog, hr::format("%s = %20.10" PLDF " (R=%10.5" PLDF " T=%" PLDF ")", name, cur, l.R, l.T));
map<pair<double, double>, double> memo;
auto ff = [&] () {
if(l.T < -5) exit(1);
if(memo.count(make_pair(l.R, l.T)))
return memo[make_pair(l.R, l.T)];
return memo[make_pair(l.R, l.T)] = f(l);
};
int steps = 0;
for(ld step=start; step>eps; step /= 2) {
loop:
bool changed = false;
while(true) { steps++; l.R += step; ld t = ff(); if(t <= cur || steps > max_steps) break; cur = t; changed = true; }
l.R -= step;
while(true) { steps++; l.R -= step; ld t = ff(); if(t <= cur || steps > max_steps) break; cur = t; changed = true; }
l.R += step;
while(true) { steps++; l.T += step; ld t = ff(); if(t <= cur || steps > max_steps) break; cur = t; changed = true; }
l.T -= step;
while(true) { steps++; l.T -= step; ld t = ff(); if(t <= cur || l.T < 1e-3 || steps > max_steps) break; cur = t; changed = true; }
l.T += step;
if(changed) goto loop;
if(name) println(hlog, hr::format("%s = %20.10" PLDF " (R=%10.5" PLDF " T=%10.5" PLDF ")", name, cur, l.R, l.T));
fflush(stdout);
}
}
}

View File

@@ -54,7 +54,7 @@ void show_likelihood() {
dialog::add_action([] () {
embedder_loop(1);
ts_vertices = ts_rbase;
place_rogueviz_vertices();
rogueviz::embeddings::reenable_embedding();
});
dialog::addBack();
@@ -83,6 +83,7 @@ void show_likelihood() {
handlePanning(sym, uni);
if(uni == '-' && held_id == -1) {
int N = isize(rogueviz::vdata);
for(int i=0; i<N; i++) if(rogueviz::vdata[i].m->base == mouseover)
held_id = i;
return;
@@ -100,7 +101,7 @@ bool dhrg_animate(int sym, int uni) {
if(ts_rbase > ts_vertices) {
dhrg_init(); graph_from_rv();
ts_vertices = ts_rbase;
place_rogueviz_vertices();
rogueviz::embeddings::reenable_embedding();
}
pushScreen(show_likelihood);

View File

@@ -1,28 +1,29 @@
#include "../rogueviz.h"
#include "embeddings.h"
namespace rogueviz {
unique_ptr<embedding> current_embedding;
namespace embeddings {
std::shared_ptr<embedding> current;
vector<vector<int> > directed_edges;
rogueviz::edgetype *any;
struct rv_embedding : public embedding {
hyperpoint as_hyperpoint(int id) override {
return currentmap->relative_matrix(vdata[id].m->base, currentmap->gamestart(), C0) * (vdata[id].m->at * C0);
struct rv_embedding : public tiled_embedding {
pair<cell*, hyperpoint> as_location(int id) override {
return { vdata[id].m->base, vdata[id].m->at * C0 };
}
};
void read_edgelist(string fname) {
void read_edgelist(const string& fname) {
rogueviz::init(RV_GRAPH);
rv_hook(hooks_clearmemory, 100, [] {
directed_edges.clear();
current_embedding = nullptr;
current = nullptr;
});
any = rogueviz::add_edgetype("embedded edges");
@@ -54,12 +55,34 @@ void read_edgelist(string fname) {
if(rogueviz::rv_quality >= 0) {
for(auto& v: vdata)
v.be(all[gmod(id++, isize(all))], Id);
current_embedding = std::make_unique<rv_embedding> ();
current = std::make_shared<rv_embedding> ();
}
}
int a = arg::add3("-edgelist", [] { arg::shift(); read_edgelist(arg::args()); });
void reenable_embedding() {
if(rogueviz::rv_quality >= 0)
for(auto& v: vdata) {
auto p = current->as_location(v.id);
v.be(p.first, rgpushxto0(p.second));
}
}
void enable_embedding(std::shared_ptr<embedding> pe) {
current = std::move(pe);
reenable_embedding();
}
void store_gamedata(struct hr::gamedata* gd) { gd->store(current); }
int a = arg::add3("-edgelist", [] { arg::shift(); read_edgelist(arg::args()); })
+ addHook(hooks_gamedata, 230, store_gamedata);
}
}
#include "polar.cpp"
#include "loglik.cpp"
#include "routing.cpp"

View File

@@ -0,0 +1,222 @@
namespace rogueviz {
namespace embeddings {
// log likelihood utilities
//--------------------------
// MLE of the binomial distribution (a successes, b failures)
ld bestll(ld a, ld b) {
if(a == 0 || b == 0) return 0;
return a * log(a/(a+b)) + b * log(b/(a+b));
}
// a successes, ab total
ld bestll2(ld a, ld ab) { return bestll(a, ab-a); }
// --- continuous logistic loglikelihood
// --------------------------------------
vector<ld> disttable0, disttable1;
using logisticfun = std::function<ld(logistic&)>;
// needs cellcoords/rvcoords/origcoords
void build_disttable() {
indenter_finish im("build_disttable");
int N = isize(rogueviz::vdata);
vector<int> tab(N, N);
disttable0.clear();
disttable1.clear();
using namespace rogueviz;
for(int i=0; i<N; i++) {
for(auto p: vdata[i].edges) {
int j = p.second->i ^ p.second->j ^ i;
if(j<i) tab[j] = i;
}
for(int j=0; j<i; j++) {
ld dist = current->distance(i, j);
if(dist < 0) continue;
(tab[j] == i ? disttable1:disttable0).push_back(dist);
}
}
sort(disttable0.begin(), disttable0.end());
sort(disttable1.begin(), disttable1.end());
}
// needs build_disttable
ld loglik_cont(logistic& l = current_logistic) {
ld llh = 1;
for(auto p: disttable1) llh += l.lyes(p);
for(auto p: disttable0) {
ld lp = l.lno(p);
llh += lp;
if(lp > -1e-10) break;
}
return llh;
}
using ll = long long;
vector<array<ll, 2>> disttable_approx;
ld llcont_approx_prec = 10000;
int threads = 32;
void build_disttable_approx() {
indenter_finish im("build_disttable_approx");
array<ll, 2> zero = {0, 0};
using namespace rogueviz;
std::vector<vector<array<ll, 2>>> results(threads);
std::vector<std::thread> v;
int N = isize(rogueviz::vdata);
for(int k=0; k<threads; k++)
v.emplace_back([&,k] () {
auto& dt = results[k];
vector<int> tab(N, N);
auto p = k ? nullptr : new progressbar(N/threads, "build_disttable_approx");
for(int i=k; i<N; i+=threads) {
if(p) (*p)++;
for(auto p: vdata[i].edges) {
int j = p.second->i ^ p.second->j ^ i;
if(j<i) tab[j] = i;
}
for(int j=0; j<i; j++) {
ld dist = current->distance(i, j);
if(dist < 0) continue;
int dista = dist * llcont_approx_prec;
if(isize(dt) < dista+1)
dt.resize(dista+1, zero);
dt[dista][(tab[j] == i) ? 1 : 0]++;
}
}
if(p) delete p;
});
for(std::thread& t:v) t.join();
int mx = 0;
for(auto& r: results) mx = max(mx, isize(r));
disttable_approx.clear();
disttable_approx.resize(mx, zero);
for(auto& r: results)
for(int i=0; i<isize(r); i++)
for(int j=0; j<2; j++)
disttable_approx[i][j] += r[i][j];
}
ld loglik_cont_approx(logistic& l) {
ld llh = 0;
int N = isize(disttable_approx);
for(int i=0; i<N; i++) {
if(disttable_approx[i][0])
llh += l.lno((i+.5)/llcont_approx_prec) * disttable_approx[i][0];
if(disttable_approx[i][1])
llh += l.lyes((i+.5)/llcont_approx_prec) * disttable_approx[i][1];
}
return llh;
}
int max_steps = 100000;
void fix_logistic_parameters(logistic& l, const logisticfun& f, const char *name, ld eps) {
indenter_finish im("fix_logistic_parameters");
ld cur = f(l);
println(hlog, hr::format("%s = %20.10" PLDF " (R=%10.5" PLDF " T=%" PLDF ")", name, cur, l.R, l.T));
for(ld step=1; step>eps; step /= 2) {
while(true) { l.R += step; ld t = f(l); if(t <= cur) break; cur = t; }
l.R -= step;
while(true) { l.R -= step; ld t = f(l); if(t <= cur) break; cur = t; }
l.R += step;
while(true) { l.T += step; ld t = f(l); if(t <= cur) break; cur = t; }
l.T -= step;
while(true) { l.T -= step; ld t = f(l); if(t <= cur) break; cur = t; }
l.T += step;
println(hlog, hr::format("%s = %20.10" PLDF " (R=%10.5" PLDF " T=%10.5" PLDF ")", name, cur, l.R, l.T));
fflush(stdout);
}
}
void fast_loglik_cont(logistic& l, const logisticfun& f, const char *name, ld start, ld eps) {
if(name) println(hlog, "fix_logistic_parameters");
indenter_finish im(name);
ld cur = f(l);
if(name) println(hlog, hr::format("%s = %20.10" PLDF " (R=%10.5" PLDF " T=%" PLDF ")", name, cur, l.R, l.T));
map<pair<double, double>, double> memo;
auto ff = [&] () {
if(l.T < -5) exit(1);
if(memo.count(make_pair(l.R, l.T)))
return memo[make_pair(l.R, l.T)];
return memo[make_pair(l.R, l.T)] = f(l);
};
int steps = 0;
for(ld step=start; step>eps; step /= 2) {
loop:
bool changed = false;
while(true) { steps++; l.R += step; ld t = ff(); if(t <= cur || steps > max_steps) break; cur = t; changed = true; }
l.R -= step;
while(true) { steps++; l.R -= step; ld t = ff(); if(t <= cur || steps > max_steps) break; cur = t; changed = true; }
l.R += step;
while(true) { steps++; l.T += step; ld t = ff(); if(t <= cur || steps > max_steps) break; cur = t; changed = true; }
l.T -= step;
while(true) { steps++; l.T -= step; ld t = ff(); if(t <= cur || l.T < 1e-3 || steps > max_steps) break; cur = t; changed = true; }
l.T += step;
if(changed) goto loop;
if(name) println(hlog, hr::format("%s = %20.10" PLDF " (R=%10.5" PLDF " T=%10.5" PLDF ")", name, cur, l.R, l.T));
fflush(stdout);
}
}
logistic cont_logistic;
int loglik_args() {
using namespace arg;
if(argis("-loglik-approx")) {
build_disttable_approx();
fast_loglik_cont(cont_logistic, loglik_cont_approx, "lcont", 1, 1e-6);
// return loglik_cont();
}
else if(argis("-loglik-precise")) {
build_disttable();
fast_loglik_cont(cont_logistic, loglik_cont, "lcont", 1, 1e-6);
// return loglik_cont();
}
else return 1;
return 0;
}
auto alol = addHook(hooks_args, 50, loglik_args);
}
}

View File

@@ -1,66 +1,78 @@
namespace dhrg {
namespace rogueviz {
namespace embeddings {
double graph_R, graph_alpha, graph_T;
vector<pair<double, double> > coords;
rogueviz::edgetype *any;
int N;
void tst() {}
void read_graph(string fn) {
struct polar_point {
ld r, theta;
};
any = rogueviz::add_edgetype("embedded edges");
rogueviz::fname = fn;
fhstream f(fn + "-coordinates.txt", "rt");
if(!f.f) {
printf("Missing file: %s-coordinates.txt\n", rogueviz::fname.c_str());
exit(1);
struct polar_embedding : public untiled_embedding {
vector<polar_point> coords;
hyperpoint as_hyperpoint(int id) override {
return spin(coords[id].theta) * xpush0(coords[id].r);
}
ld zero_distance(int id) { return coords[id].r; }
ld distance(int i, int j) {
ld da = coords[i].r;
ld db = coords[j].r;
ld phi = coords[i].theta - coords[j].theta;
ld co = sinh(da) * sinh(db) * (1 - cos(phi));
ld v = cosh(da - db) + co;
if(v < 1) return 0;
return acosh(v);
}
};
/** read polar coordinates, in the format returned by the BFKL embdder. */
void read_polar(const string& fn) {
fhstream f(fn, "rt");
if(!f.f) return file_error(fn);
int N;
printf("Reading coordinates...\n");
string ignore;
if(!scan(f, ignore, ignore, ignore, ignore, N, graph_R, graph_alpha, graph_T)) {
printf("Error: incorrect format of the first line\n"); exit(1);
}
rogueviz::vdata.reserve(N);
while(true) {
string s = scan<string>(f);
if(s == "D11.11") tst();
if(s == "" || s == "#ROGUEVIZ_ENDOFDATA") break;
int id = rogueviz::getid(s);
rogueviz::vertexdata& vd(rogueviz::vdata[id]);
vd.name = s;
vd.cp = rogueviz::colorpair(rogueviz::dftcolor);
double r, alpha;
if(!scan(f, r, alpha)) { printf("Error: incorrect format of r/alpha\n"); exit(1); }
coords.push_back(make_pair(r, alpha));
transmatrix h = spin(alpha * degree) * xpush(r);
vd.be(currentmap->gamestart(), h);
if(graph_R && graph_T) cont_logistic.setRT(graph_R, graph_T);
if(N == 0) N = isize(vdata);
if(N != isize(vdata)) throw hr_exception("incorrect N");
auto pe = std::make_shared<polar_embedding> ();
pe->coords.resize(N);
for(int i=0; i<N; i++) {
string s = scan<string>(f);
if(s == "" || s == "#ROGUEVIZ_ENDOFDATA") throw hr_exception("data failure");
int id = rogueviz::labeler.at(s);
double r, theta;
if(!scan(f, r, theta)) { printf("Error: incorrect format of r/alpha\n"); exit(1); }
pe->coords[id] = polar_point{.r = r, .theta = theta * degree};
}
fhstream g(fn + "-links.txt", "rt");
if(!g.f) {
println(hlog, "Missing file: ", rogueviz::fname, "-links.txt");
exit(1);
}
println(hlog, "Reading links...");
int qlink = 0;
while(true) {
int i = rogueviz::readLabel(g), j = rogueviz::readLabel(g);
if(i == -1 || j == -1) break;
addedge(i, j, 1, any);
qlink++;
}
enable_embedding(std::move(pe));
}
int a_polar =
arg::add3("-el-polar", [] { arg::shift(); read_polar(arg::args()); })
+ arg::add3("-el-bfkl", [] { arg::shift(); read_edgelist(arg::args() + "-links.txt"); read_polar(arg::args() + "-coordinates.txt"); });
void unsnap() {
for(int i=0; i<N; i++) {
using rogueviz::vdata;
transmatrix h = spin(coords[i].second * degree) * xpush(coords[i].first);
vdata[i].be(currentmap->gamestart(), h);
}
}
}
}

View File

@@ -1,7 +1,9 @@
// $(VARIANT) -nogui -dhrg embedded-graphs/facebook_combined_result -contll -iterate 99 -contll -esave > $@
namespace dhrg {
namespace rogueviz {
namespace embeddings {
struct pairdata { ld success, route_length; };
@@ -14,12 +16,8 @@ vector<pairdata> pairs;
vector<int> last_goal;
vector<int> next_stop;
int gr_N;
using neighborhoodfun = std::function<vector<int> (int)>;
void prepare_pairs(int N, const neighborhoodfun& nei) {
gr_N = N;
void prepare_pairs() {
int N = isize(rogueviz::vdata);
pairs.resize(N);
actual.resize(N);
for(int i=0; i<N; i++) actual[i].resize(N, NOYET);
@@ -35,8 +33,8 @@ void prepare_pairs(int N, const neighborhoodfun& nei) {
visit(i, 0);
for(int k=0; k<isize(bfsqueue); k++) {
int a = bfsqueue[k];
for(auto b: nei(a))
visit(b, p[a] + 1);
for(auto ed: rogueviz::vdata[a].edges)
visit(ed.first, p[a] + 1);
}
}
last_goal.clear();
@@ -45,17 +43,6 @@ void prepare_pairs(int N, const neighborhoodfun& nei) {
next_stop.resize(N, -1);
}
void prepare_pairs() {
prepare_pairs(N, [] (int a) {
vector<int> res;
for(auto ed: rogueviz::vdata[a].edges) {
int b = ed.second->i ^ ed.second->j ^ a;
res.push_back(b);
}
return res;
});
}
void route_from(int src, int goal, const vector<ld>& distances_from_goal) {
if(last_goal[src] == goal) return;
if(src == goal) {
@@ -70,8 +57,8 @@ void route_from(int src, int goal, const vector<ld>& distances_from_goal) {
indent += 2; */
vector<int> candidates;
for(auto ed: rogueviz::vdata[src].edges) {
int e = ed.second->i ^ ed.second->j ^ src;
for(auto& ed: rogueviz::vdata[src].edges) {
int e = ed.first;
ld d = e == goal ? -1 : distances_from_goal[e];
if(d < bestd) bestd = d, candidates.clear();
if(d == bestd) candidates.push_back(e);
@@ -92,14 +79,15 @@ void route_from(int src, int goal, const vector<ld>& distances_from_goal) {
last_goal[src] = goal;
}
void greedy_routing_to(iddata& d, int goal, const distfun& distance_function) {
vector<ld> distances_from_goal(gr_N);
for(int src=0; src<gr_N; src++)
distances_from_goal[src] = distance_function(goal, src);
for(int src=0; src<gr_N; src++)
void greedy_routing_to(iddata& d, int goal) {
int N = isize(rogueviz::vdata);
vector<ld> distances_from_goal(N);
for(int src=0; src<N; src++)
distances_from_goal[src] = current->distance(goal, src);
for(int src=0; src<N; src++)
route_from(src, goal, distances_from_goal);
for(int j=0; j<gr_N; j++) if(j != goal){
for(int j=0; j<N; j++) if(j != goal){
d.tot++;
ld p = pairs[j].success;
d.suc += p;
@@ -108,10 +96,12 @@ void greedy_routing_to(iddata& d, int goal, const distfun& distance_function) {
}
}
void greedy_routing(iddata& d, const distfun& distance_function) {
for(int goal=0; goal<gr_N; goal++) greedy_routing_to(d, goal, distance_function);
void greedy_routing(iddata& d) {
int N = isize(rogueviz::vdata);
for(int goal=0; goal<N; goal++) greedy_routing_to(d, goal);
}
#if 0
void routing_test(string s) {
iddata datas[6];
@@ -163,11 +153,12 @@ void routing_test(string s) {
println(hlog, "HDR;", separated(";", reps), ";N;GROWTH\n");
println(hlog, "RES;", separated(";", values), ";", N, ";", cgi.expansion->get_growth());
}
#endif
int current_goal;
iddata prepared;
void prepare_goal(int goal) {
greedy_routing_to(prepared, current_goal = goal, [] (int i, int j) { return hdist(vertexcoords[i], vertexcoords[j]); });
greedy_routing_to(prepared, current_goal = goal);
}
vector<int> path(int src) {
@@ -183,4 +174,18 @@ int get_actual(int src) {
return actual[src][current_goal];
}
int routing_args() {
using namespace arg;
if(argis("-routing")) {
// shift(); routing_test(args());
}
else return 1;
return 0;
}
auto arou = addHook(hooks_args, 50, routing_args);
}
}

View File

@@ -84,14 +84,6 @@ namespace rogueviz {
int readLabel(fhstream& f);
struct embedding {
virtual hyperpoint as_hyperpoint(int id) = 0;
virtual ld distance(int i, int j) { return hdist(as_hyperpoint(i), as_hyperpoint(j)); }
virtual ld zero_distance(int id) { return hdist0(as_hyperpoint(id)); }
};
extern unique_ptr<embedding> current_embedding;
#if CAP_TEXTURE
struct rvimage {
basic_textureinfo tinf;

View File

@@ -8,7 +8,7 @@ namespace sag {
int recover_from;
vector<pair<dhrg::logistic, ld>> results;
vector<pair<embeddings::logistic, ld>> results;
ld bestcost;
@@ -228,9 +228,9 @@ void output_stats() {
println(hlog, "solution: ", sagid);
int DN = isize(sagid);
auto [mAP, MeanRank] = compute_mAP();
dhrg::iddata routing_result;
if(!known_pairs) { known_pairs = true; dhrg::prepare_pairs(DN, [] (int i) { return edges_yes[i]; }); }
dhrg::greedy_routing(routing_result, [] (int i, int j) { return sagdist[sagid[i]][sagid[j]]; });
embeddings::iddata routing_result;
if(!known_pairs) { known_pairs = true; embeddings::prepare_pairs(); }
embeddings::greedy_routing(routing_result);
print(hlog, "CSV;", logid++, ";", isize(sagnode), ";", DN, ";", isize(edgeinfos), ";", lgsag_pre.R, ";", lgsag_pre.T, ";", lgsag.R, ";", lgsag.T, ";", cost, ";", mAP, ";", MeanRank, ";", routing_result.suc / routing_result.tot, ";", routing_result.routedist / routing_result.bestdist);
if(lastmethod) print(hlog, ";", lastmethod);
if(mul_used) print(hlog, ";", mul_used);

View File

@@ -3,7 +3,7 @@
#include "../rogueviz.h"
#include "../dhrg/dhrg.h"
#include "../embeddings/embeddings.h"
#include "../statistics.cpp"
namespace rogueviz {
@@ -20,11 +20,13 @@ int method_count = 3;
ld match_a = 1, match_b = 0;
/* parameters for smLogistic */
dhrg::logistic lgsag(1, 1), lgsag_pre(1, 1);
embeddings::logistic lgsag(1, 1), lgsag_pre(1, 1);
ld yes_for(ld d) { return lgsag.yes(d); }
vector<ld> loglik_tab_y, loglik_tab_n;
dhrg::logistic best;
embeddings::logistic best;
debugflag debug_opt("sag_opt");
@@ -152,7 +154,7 @@ void optimize_sag_loglik_logistic() {
if(debug_opt) println(hlog, "loglikelihood best = ", fts(loglik));
auto logisticf = [&] (dhrg::logistic& l) {
auto logisticf = [&] (embeddings::logistic& l) {
ld loglik = 0;
for(int d=0; d<max_sag_dist; d++) {
int p = pedge[d], pq = indist[d];
@@ -165,7 +167,7 @@ void optimize_sag_loglik_logistic() {
if(debug_opt) println(hlog, "cost = ", cost, " logisticf = ", logisticf(lgsag), " R= ", lgsag.R, " T= ", lgsag.T);
if(should_good && abs(cost + logisticf(lgsag)) > 0.1) throw hr_exception("computation error");
dhrg::fast_loglik_cont(lgsag, logisticf, nullptr, 1, 1e-5);
embeddings::fast_loglik_cont(lgsag, logisticf, nullptr, 1, 1e-5);
if(debug_opt) println(hlog, "loglikelihood logistic = ", logisticf(lgsag), " R= ", lgsag.R, " T= ", lgsag.T);
if(method == smLogistic) {