/** * This program was used to generate the rule tables in apeirodic-hat.cpp. * * Some data was generated by this program itself, based on manual keyboard+mouse control. * Some of minor manual control tools have been removed, but the process was as follows: * * * Run with `-symbol "12,6,4" -dual -canvas 101010 -smart 1 stamplen=0` and draw the hat shape, the table output is hatcorners * * Place hats into clusters as shown in the paper, obtaining the table hats[0] * * Place clusters into superclusters as shown in the paper, obtaining the table hats[1] * * Repeat for hats[2], hats[3], hats[4] and hats[5] (the paper does not specify precisely the coordinates to arrange the clusters; but we can multiply the previous hats by scaling factor * * for an approximate, and fix manually so that it matches) * * 'CON Lx' lines state the rules deduced; the rules should be the same for L1 and L2 (except the matrix codes returned by matcode), so we conjecture that this set of rules is complete * * Fill the table `hatid` to declare the correspondence between L1 and L2 matrices * * Run again, and we get rules (prefixed by RULE1 and RULE0) **/ #include "../rogueviz/rogueviz.h" namespace rogueviz { int toplev = 5; vector hatcorners_add; vector hatcorners[2]; vector hats[8]; vector hattype; hyperpoint pt(ld x, ld y) { return hpxy(x, y); } transmatrix rot; transmatrix sca; transmatrix U; transmatrix mt(ld a, ld b, ld c, ld d, ld e, ld f, ld g, ld h, ld i) { transmatrix T = Id; T[0][0] = a; T[0][1] = b; T[0][2] = c; T[1][0] = d; T[1][1] = e; T[1][2] = f; T[2][0] = g; T[2][1] = h; T[2][2] = i; return T; } map hatid; void init() { rot = Id; hatcorners[0] = { pt(-1.1160254038,1.4330127019), pt(-0.0915063509,2.0245190528), pt(0.2500000000,1.4330127019), pt(-0.0915063509,0.8415063509), pt(0.9330127019,0.2500000000), pt(0.9330127019,-0.9330127019), pt(0.2500000000,-0.9330127019), pt(-0.0915063509,-1.5245190528), pt(-1.1160254038,-0.9330127019), pt(-2.1405444566,-1.5245190528), pt(-2.4820508076,-0.9330127019), pt(0,0), pt(-1.7990381057,0.2500000000), pt(-1.1160254038,0.2500000000), }; hatcorners[0][11] = mid(hatcorners[0][10], hatcorners[0][12]); hatcorners[1] = hatcorners[0]; for(auto& h: hatcorners[1]) h = MirrorX * h; reverse(hatcorners[1].begin(), hatcorners[1].end()); hats[0] = { mt(0.5000000000,-0.8660254038,-1.3660254038, -0.8660254038,-0.5000000000,-0.0000000000, 0.0000000000,0.0000000000,1.0000000000) * MirrorX, mt(0.5000000000,-0.8660254038,0.6830127019, 0.8660254038,0.5000000000,1.6830127019, 0.0000000000,0.0000000000,1.0000000000), mt(-1.0000000000,0.0000000000,-2.2320508076, -0.0000000000,-1.0000000000,-1.8660254038, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,-0.8660254038,-4.5310889132, 0.8660254038,-0.5000000000,-1.6160254038, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,-0.8660254038,-3.4150635095, 0.8660254038,0.5000000000,1.6830127019, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,-0.0000000000,-2.0490381057, 0.0000000000,1.0000000000,3.5490381057, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,0.8660254038,0.2500000000, -0.8660254038,0.5000000000,3.2990381057, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,-0.8660254038,-5.4641016151, 0.8660254038,0.5000000000,0.5000000000, 0.0000000000,0.0000000000,1.0000000000), }; hats[1] = { mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,0.8660254038,-0.8660254038, -0.8660254038,-0.5000000000,7.0980762114, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,0.8660254038,-5.8971143170, -0.8660254038,0.5000000000,4.4820508076, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,-0.0000000000,-6.1471143170, 0.0000000000,1.0000000000,-1.1830127019, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,-0.8660254038,-4.5310889132, 0.8660254038,-0.5000000000,-3.9820508076, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,-0.8660254038,-9.5621778265, 0.8660254038,0.5000000000,-6.5980762114, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,-0.0000000000,-14.3432667397, 0.0000000000,1.0000000000,-3.5490381057, 0.0000000000,0.0000000000,1.0000000000), }; hattype = {7, 8, 8, 8, 8, 8, 8}; ld q7 = 1, q8 = 0; ld val; for(int a=0; a<100; a++) { ld nq7 = q7 + q8; ld nq8 = q7 * 5 + q8 * 6; println(hlog, format("%.20f", val = (nq7 + nq8) / (q7 + q8))); q7 = nq7; q8 = nq8; } val = sqrt(val); println(hlog, "root: ", format("%.20f", val)); for(int a=-50; a<50; a++) for(int b=1; b<50; b++) for(int c=-50; c<50; c++) for(int d=1; d<50; d++) { ld err = abs(a*1./b + c * sqrt(1./d) - val); if(err < 1e-6) println(hlog, tie(a,b,c,d), " : ", err); } val = (3 + sqrt(5)) / 2; // scaling each axis sca = Id; sca[0][0] = sca[1][1] = val; hats[2] = { mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,0.8660254038,1.1830127025, -0.8660254038,-0.5000000000,15.3791651251, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,0.8660254038,-12.0442286339, -0.8660254038,0.5000000000,10.3971143173, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,0.0000000000,-14.3432667399, 0.0000000000,1.0000000000,-3.5490381057, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,-0.8660254038,-12.7272413356, 0.8660254038,-0.5000000000,-13.4461524228, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,-0.8660254038,-25.9544826718, 0.8660254038,0.5000000000,-18.4282032304, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,0.0000000000,-36.8826859024, 0.0000000000,1.0000000000,-9.4641016152, 0.0000000000,0.0000000000,1.0000000000), }; hats[3] = { mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,0.8660254038,7.3301270200, -0.8660254038,-0.5000000000,37.8564064623, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,0.8660254038,-28.4365334803, -0.8660254038,0.5000000000,26.9592921447, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,0.0000000000,-36.8826859027, 0.0000000000,1.0000000000,-9.4641016152, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,-0.8660254038,-33.2176223915, 0.8660254038,-0.5000000000,-39.4724318658, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,-0.8660254038,-68.9842828915, 0.8660254038,0.5000000000,-50.3695461828, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,0.0000000000,-96.3047909683, 0.0000000000,1.0000000000,-24.8432667403, 0.0000000000,0.0000000000,1.0000000000), }; hats[4] = { mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,0.8660254038,23.7224318656, -0.8660254038,-0.5000000000,97.0070415601, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,0.8660254038,-71.4663337016, -0.8660254038,0.5000000000,70.7307621167, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,0.0000000000,-96.3047909682, 0.0000000000,1.0000000000,-24.8432667399, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,-0.8660254038,-86.4926131352, 0.8660254038,-0.5000000000,-108.0871685769, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,-0.8660254038,-181.6813787030, 0.8660254038,0.5000000000,-134.3634480195, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,0.0000000000,-252.0316870025, 0.0000000000,1.0000000000,-65.0656986057, 0.0000000000,0.0000000000,1.0000000000), }; hats[5] = { mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,0.8660254038,66.7522320948, -0.8660254038,-0.5000000000,251.9817055201, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,0.8660254038,-184.1634295166, -0.8660254038,0.5000000000,185.4829942043, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,0.0000000000,-252.0316870019, 0.0000000000,1.0000000000,-65.0656986045, 0.0000000000,0.0000000000,1.0000000000), mt(-0.5000000000,-0.8660254038,-225.8272043260, 0.8660254038,-0.5000000000,-287.9050992716, 0.0000000000,0.0000000000,1.0000000000), mt(0.5000000000,-0.8660254038,-476.7428659331, 0.8660254038,0.5000000000,-354.4038105811, 0.0000000000,0.0000000000,1.0000000000), mt(1.0000000000,0.0000000000,-659.7902700392, 0.0000000000,1.0000000000,-170.3538290768, 0.0000000000,0.0000000000,1.0000000000), }; hats[6] = hats[5]; auto acs = inverse(sca); println(hlog, "shifts:"); indenter ind(2); for(int i=0; i<7; i++) { transmatrix S = gpushxto0(hats[1][i] * C0) * hats[1][i]; // println(hlog, "S = ", kz(S)); transmatrix S0 = inverse(S); // transmatrix S1 = S; auto& t = hats[6][i]; auto& t3 = hats[5][i]; auto& t2 = hats[4][i]; auto& t1 = hats[3][i]; hyperpoint fix2 = t2 * C0 - sca * t1 * C0; hyperpoint cfix3 = acs * fix2; hyperpoint rfix3 = t3 * C0 - sca * t2 * C0; t = sca * t * acs * acs * rgpushxto0(rfix3) * sca; println(hlog, kz(rfix3-cfix3), " from ", fix2, " .. ", S0 * cfix3 - acs * fix2); // t = t * rgpushxto0(sca * (t3 * C0 - bt3 * C0)); // t = t * } hatid["R0A000L0.000"] = -1; int nextid = 8; hatid["R0A011L6.147"] = hatid["R0A014L14.343"] = nextid++; hatid["R0A016L8.196"] = hatid["R0A015L22.539"] = nextid++; hatid["R0A016L8.196"] = hatid["R0A015L22.539"] = nextid++; hatid["R0A191L6.147"] = hatid["R0A194L14.343"] = nextid++; hatid["R0A196L8.196"] = hatid["R0A195L22.539"] = nextid++; hatid["R1A023L6.903"] = hatid["R1A019L15.060"] = nextid++; hatid["R1A126L5.555"] = hatid["R1A131L15.741"] = nextid++; hatid["R1A185L7.579"] = hatid["R1A191L21.879"] = nextid++; hatid["R1A238L3.558"] = hatid["R1A232L11.654"] = nextid++; hatid["R1A327L4.885"] = hatid["R1A320L10.974"] = nextid++; hatid["R2A037L6.054"] = hatid["R2A025L14.053"] = nextid++; hatid["R2A092L2.046"] = hatid["R2A096L3.188"] = nextid++; hatid["R2A138L8.858"] = hatid["R2A145L25.101"] = nextid++; hatid["R2A221L4.953"] = hatid["R2A226L12.883"] = nextid++; hatid["R2A300L2.571"] = hatid["R2A279L2.571"] = nextid++; hatid["R3A226L7.005"] = hatid["R3A233L16.845"] = nextid++; hatid["R4A000L5.143"] = hatid["R4A339L10.197"] = nextid++; hatid["R4A097L4.093"] = hatid["R4A085L4.171"] = nextid++; hatid["R4A152L9.906"] = hatid["R4A156L21.728"] = nextid++; hatid["R4A198L11.809"] = hatid["R4A205L27.793"] = nextid++; hatid["R4A281L4.171"] = hatid["R4A286L6.625"] = nextid++; hatid["R5A087L5.006"] = hatid["R5A080L5.503"] = nextid++; hatid["R5A143L7.731"] = hatid["R5A139L13.041"] = nextid++; hatid["R5A246L6.309"] = hatid["R5A251L9.388"] = nextid++; hatid["R5A305L6.626"] = hatid["R5A311L15.426"] = nextid++; hatid["R5A358L8.119"] = hatid["R5A352L19.349"] = nextid++; println(hlog, "nextid = ", nextid); }; void draw_cross(hyperpoint h) { transmatrix T = rgpushxto0(h); shiftmatrix sId = shiftless(Id); for(int i=0; i<12; i++) queueline(sId * T * C0, sId * T * xspinpush0(30._deg * i, 0.1), 0xFFFFFFFF); } void draw_shape(transmatrix T, vector sh, color_t lc, color_t fc) { for(hyperpoint h: sh) curvepoint(h); curvepoint(sh[0]); queuecurve(shiftless(Id) * T, lc, fc, PPR::LINE); } /* void draw_superhat(transmatrix T, const vector& ms, int q, color_t lc, color_t fc) { for(auto& m: ms) draw_shape(T * m, hatcorners, lc, fc); } */ hyperpoint sh; color_t coltables[8] = { 0xFF000080, 0x00FF0080, 0x0000FF80, 0xFFFF0080, 0xFF00FF80, 0x00FFFF80, 0xFFFFFF80, 0x4080C080 }; vector curlabel; ld ldist = 9999; hyperpoint hfound, hfound1; int connection_mode = 0; int found_pairs, found_pairs_swap; using pthash = int; pthash makehash(hyperpoint h) { return int(floor(h[0] * 10 + .31)) + int(floor(h[1] * 10 + .31)) * 10000; } map, vector > seen_edges; string name(int x) { return s0 + char('A' + x); } string matcode(transmatrix T) { vector res(3); hyperpoint h = kz(T * C0); transmatrix S = gpushxto0(T * C0) * T; ld alpha = atan2(S * xpush0(1)) / degree; int ialpha = gmod(floor(alpha + .5), 360); int hangle = gmod(floor(atan2(h) / degree + .3), 360); h[2] = ialpha/60; swap(h[1], h[2]); swap(h[0], h[1]); // return lalign(0, h); return format("R%dA%03dL%.3f", ialpha/60, hangle, hypot_d(2, h)); } int ghatid(string s) { if(hatid.count(s)) return hatid[s]; return -999; } void edge_connect(vector l1, vector l2) { transmatrix T1 = Id; transmatrix T2 = Id; transmatrix W = Id; int idx = 0; for(int i=toplev; i>0; i--) { T1 = T1 * hats[i][l1[idx]]; T2 = T2 * hats[i][l2[idx]]; transmatrix W1 = inverse(T1) * T2; if(!eqmatrix(W1, Id)) println(hlog, "CON L", i, " ", matcode(W1), " :: ", matcode(W), " ", tie(l1[idx], l2[idx]), " REV ", matcode(inverse(W1))); if(i == 1) println(hlog, "RULE1 {", l1[idx], ", ", l2[idx], ", ", ghatid(matcode(W1)), ", ", ghatid(matcode(W)), ", ", ghatid(matcode(inverse(W1))), "},"); W = W1; idx++; } println(hlog, "CON L0 ", make_pair(make_pair(l1[idx], name(l1[idx+1])), make_pair(l2[idx], name(l2[idx+1]))), " :: ", matcode(W)); println(hlog, "RULE0 {", l1[idx], ", ", l1[idx+1], ", ", l2[idx], ", ", l2[idx+1], ", ", ghatid(matcode(W)), "},"); } vector > extedges; void edge_label(vector& lbl, hyperpoint a, hyperpoint b) { auto ha = makehash(a); auto hb = makehash(b); if(connection_mode >= 2) return; if(connection_mode == 1) { if(seen_edges.count({ha, hb})) { extedges.emplace_back(a, b); /* vid.linewidth *= 10; queueline(shiftless(Id) * a, shiftless(Id) * b, 0xFF00FF80); vid.linewidth /= 10; */ } return; } if(seen_edges.count({hb, ha})) { edge_connect(lbl, seen_edges[{hb, ha}]); edge_connect(seen_edges[{hb, ha}], lbl); seen_edges.erase({hb, ha}); found_pairs++; return; } if(seen_edges.count({ha, hb})) { println(hlog, "CON ", lbl, " TO ", seen_edges[{hb, ha}], " SWAP"); seen_edges.erase({ha, hb}); found_pairs_swap++; return; } seen_edges[{ha, hb}] = lbl; } void point_label(vector& lbl, hyperpoint h) { if(lbl == curlabel) draw_cross(h); ld dist = hdist(unshift(mouseh), h); if(dist < ldist) { ldist = dist; curlabel = lbl; hfound = h; println(hlog, "found: ", lbl, " at: ", dist); } } void draw_superhat_label(transmatrix T, const vector& ms, int q, color_t lc, color_t fc, vector& label) { for(int i=0; i& label) { if(levs == 0) { draw_superhat_label(T, hats[0], t, 0xFFFFFFFF, col, label); return; } if(connection_mode == 2 && levs == toplev-1) { int eid = 0; for(auto e: extedges) { queueline(shiftless(Id) * T * e.first, shiftless(Id) * T * e.second, col); label.push_back(eid++); point_label(label, T * e.first); label.pop_back(); } return; } transmatrix scap = Id; for(int i=1; i= 2) draw_shape(Id, hatcorners_add, 0xFF0000FF, 0xFF000080); transmatrix B = rgpushxto0( unshift(ggmatrix(cwt.at)) * C0 ); vector glabel; draw_recurse_label(B, toplev, 8, 0, glabel); if(connection_mode == 0) { println(hlog, "CON found = ", found_pairs, " swap = ", found_pairs_swap, " not found = ", isize(seen_edges)); // seen_edges.clear(); found_pairs = 0; connection_mode = 1; } else if(connection_mode == 1) { connection_mode = 2; toplev++; } draw_cross(C0); } string writematrix(transmatrix T) { return format("mt(%.10f,%.10f,%.10f, %.10f,%.10f,%.10f, %.10f,%.10f,%.10f)", T[0][0], T[0][1], T[0][2], T[1][0], T[1][1], T[1][2], T[2][0], T[2][1], T[2][2] ); } void hatter() { cmode = sm::NORMAL | sm::CENTER | sm::PANNING; clearMessages(); dialog::init(); gamescreen(); shiftpoint s = mapeditor::full_mouseh(); sh = unshift(s); dialog::add_key_action('a', [] { hatcorners_add.push_back(sh); println(hlog, "hatcorners = {"); for(auto h: hatcorners_add) println(hlog, format(" pt(%.10f,%.10f),", h[0], h[1])); println(hlog, " }"); }); /* dialog::add_key_action('b', [] { if(hats.empty()) return; hats.pop_back(); hattype.pop_back(); }); */ dialog::add_key_action('[', [] { // hyperpoint h = currentmap->get_corner(cwt.at, 0); // rot = rot * gpushxto0(h); rot = rot * spin(60._deg); // rot = rot * rgpushxto0(h); }); dialog::add_key_action(']', [] { // hyperpoint h = currentmap->get_corner(cwt.at, 0); // rot = rot * gpushxto0(h); rot = MirrorX * rot; // rot = rot * rgpushxto0(h); }); dialog::add_key_action('7', [] { next_hattype = 7; }); dialog::add_key_action('8', [] { next_hattype = 8; }); dialog::add_key_action('f', [] { hfound1 = hfound; }); dialog::add_key_action('b', [] { int id = curlabel[0]; hats[toplev][id] = rgpushxto0(hfound1 - hfound) * hats[toplev][id]; println(hlog, "hats[", toplev, "] = {"); for(auto h: hats[toplev]) println(hlog, " ", writematrix(h), ","); println(hlog, " }"); }); dialog::add_key_action('q', [] { exit(0); }); dialog::add_key_action('g', [] { ldist = 9999; }); keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); }; } void enable_hatter() { init(); mapeditor::snapping = true; rv_hook(hooks_frame, 100, hatframe); pushScreen(hatter); } auto hathook = arg::add3("-hatter", enable_hatter); }