mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 14:02:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			285 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			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];
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| }
 | |
| }
 | 
