hyperrogue/rogueviz/som/embeddings.cpp

285 lines
7.3 KiB
C++

// here the embeddings used in our experiments are implemented
// Copyright (C) 2011-2022 Tehora and Zeno Rogue, see 'hyper.cpp' for details
#include "kohonen.h"
namespace rogueviz {
namespace embeddings {
embedding_type etype = eNatural;
/** landscape embedding */
map<cell*, kohvec> landscape_at;
map<cellwalker, kohvec> delta_at;
map<cellwalker, int> delta_id;
int qdelta;
void init_landscape(int dimensions) {
etype = eLandscape;
landscape_at.clear();
delta_at.clear();
delta_id.clear();
qdelta = 0;
landscape_at[currentmap->gamestart()].resize(dimensions, 0);
println(hlog, "initialized for ", currentmap->gamestart());
}
kohvec& get_landscape_at(cell *h);
void init_landscape_det(const vector<cell*>& ac) {
etype = eLandscape;
landscape_at.clear();
delta_at.clear();
delta_id.clear();
qdelta = 0;
landscape_at[currentmap->gamestart()].resize(0, 0);
for(cell *c: ac) get_landscape_at(c);
int dimensions = isize(delta_at);
landscape_at.clear();
landscape_at[currentmap->gamestart()].resize(dimensions, 0);
println(hlog, "qdelta = ", qdelta, " size of delta_at = ", isize(delta_at));
for(auto& d: delta_at) {
d.second.resize(dimensions, 0);
// d.second[id++] = 1;
d.second[delta_id[d.first]] = 1;
}
println(hlog, "initialized for ", currentmap->gamestart(), ", dimensions = ", dimensions);
}
void normalize(cellwalker& cw) {
int d = celldist(cw.at);
back:
if(GDIM == 3) {
auto& da = currentmap->dirdist(cw.at);
for(int j=0; j<S7; j++) if(da[j] == 1) {
cellwalker str = currentmap->strafe(cw, j);
int d1 = celldist(str.at);
if(d1 == d+1) continue;
else if(d1 == d-1) { d = d1; cw = str; goto back; }
else println(hlog, tie(d, d1));
}
}
else if(S3 == OINF) return;
else if(S3 == 4) for(int s: {1, -1}) {
cellwalker str = (cw + s) + wstep + s;
int d1 = celldist(str.at);
if(d1 < d) { d = d1; cw = str; goto back; }
}
else {
while(true) {
cellwalker str = (cw + 1) + wstep + 2;
int d1 = celldist(str.at);
if(d1 > d) break;
d = d1; cw = str;
}
while(true) {
cellwalker str = (cw - 2) + wstep - 1;
int d1 = celldist(str.at);
if(d1 > d) break;
d = d1; cw = str;
}
}
}
ld hrandd() {
return ((hrngen() & HRANDMAX) + .5) / HRANDMAX;
}
ld gaussian_random() {
ld u1 = hrandd();
ld u2 = hrandd();
return sqrt(-2*log(u1)) * cos(TAU*u2);
}
void apply_delta(cellwalker cw, kohvec& v) {
normalize(cw);
auto& da = delta_at[cw];
if(!delta_id.count(cw)) {
delta_id[cw] = qdelta++;
da.resize(isize(v));
for(int i=0; i<min(200, isize(da)); i++)
if(i < isize(da)) da[i] = gaussian_random();
}
for(int i=0; i<isize(v); i++) v[i] += da[i];
}
kohvec& get_landscape_at(cell *h) {
if(landscape_at.count(h)) return landscape_at[h];
int hd = celldist(h);
// if(hd > 2) exit(1);
for(int i=0; i<h->type; i++) {
cell *h1 = h->cmove(i);
auto hd1 = celldist(h1);
if(hd1 < hd) {
cellwalker cw(h, i);
auto& res = landscape_at[h];
res = get_landscape_at(h1);
if(S3 == 3) {
apply_delta(cw, res);
apply_delta(cw+1, res);
}
else
apply_delta(cw, res);
break;
}
}
return landscape_at[h];
}
/** signposts embedding */
vector<cell*> signposts;
void mark_signposts(bool full, const vector<cell*>& ac) {
etype = eSignpost;
println(hlog, "marking signposts");
signposts.clear();
int maxd = 0;
if(!closed_manifold)
for(cell *c: ac) maxd = max(celldist(c), maxd);
for(cell *c: ac)
if(full || c->type != 6)
if(closed_manifold || celldist(c) == maxd)
signposts.push_back(c);
}
/** special signposts */
void mark_signposts_subg(int a, int b, const vector<cell*>& ac) {
etype = eSignpost;
println(hlog, "marking bitrunc signposts");
signposts.clear();
int maxd = 0;
if(!closed_manifold)
for(cell *c: ac) maxd = max(celldist(c), maxd);
for(cell *c: ac) {
auto li = gp::get_local_info(c);
auto rel = li.relative * gp::loc(a, b);
auto rel2 = rel * gp::param.conj();
rel2 = rel2 / (gp::param * gp::param.conj()).first;
if(rel2 * gp::param == rel)
signposts.push_back(c);
}
}
/** rug embedding */
map<cell*, hyperpoint> rug_coordinates;
void generate_rug(int i, bool close) {
etype = eHypersian;
rug::init();
while(rug::precision_increases < i) rug::physics();
if(close) rug::close();
for(auto p: rug::rug_map)
rug_coordinates[p.first] = p.second->native;
}
/** main function */
void get_coordinates(kohvec& v, cell *c, cell *c0) {
switch(etype) {
case eLandscape: {
v = get_landscape_at(c);
columns = isize(v);
break;
}
case eSignpost:
columns = isize(signposts);
alloc(v);
for(int i=0; i<isize(signposts); i++)
v[i] = celldistance(signposts[i], c);
break;
case eHypersian: {
columns = 3;
alloc(v);
auto h = rug_coordinates.at(c);
for(int i=0; i<3; i++) v[i] = h[i];
break;
}
case eNatural: {
hyperpoint h = calc_relative_matrix(c, c0, C0) * C0;
using namespace euc;
auto& T0 = eu_input.user_axes;
if(sphere) {
columns = MDIM;
alloc(v);
for(int i=0; i<MDIM; i++)
v[i] = h[i];
}
else if(euclid && closed_manifold && S3 == 3 && WDIM == 2 && T0[0][1] == 0 && T0[1][0] == 0 && T0[0][0] == T0[1][1]) {
columns = 6;
alloc(v);
int s = T0[0][0];
for(int i=0; i<3; i++) {
hyperpoint h1 = spin(120._deg*i) * h;
ld x = h1[1];
ld alpha = TAU * x / s / (sqrt(3) / 2);
// println(hlog, kz(x), " -> ", kz(alpha));
v[2*i] = cos(alpha);
v[2*i+1] = sin(alpha);
}
// println(hlog, kz(h), " -> ", v);
}
else if(euclid && closed_manifold && WDIM == 2) {
columns = 4;
alloc(v);
rug::clifford_torus ct;
h = ct.torus_to_s4(ct.actual_to_torus(h));
for(int i=0; i<4; i++)
v[i] = h[i];
}
else if(euclid && closed_manifold && WDIM == 3) {
columns = 6;
alloc(v);
using namespace euc;
auto& T0 = eu_input.user_axes;
for(int i=0; i<3; i++) {
int s = T0[i][i];
ld alpha = TAU * h[i] / s;
v[2*i] = cos(alpha) * s;
v[2*i+1] = sin(alpha) * s;
}
}
else if(euclid && !quotient) {
columns = WDIM;
alloc(v);
for(int i=0; i<WDIM; i++)
v[i] = h[i];
}
else {
println(hlog, "error: unknown geometry to get coordinates from");
exit(1);
}
break;
}
case eProjection: {
hyperpoint h = calc_relative_matrix(c, c0, C0) * C0;
hyperpoint res;
applymodel(shiftless(h), res);
columns = WDIM;
if(models::is_3d(pconf)) columns = 3;
alloc(v);
for(int i=0; i<columns; i++) v[i] = res[i];
}
}
}
}
}