From 59a9605b1312c728c6c60f543ae1c883c26f91d5 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Wed, 15 Jan 2020 17:58:41 +0100 Subject: [PATCH] arb::relative_matrix --- arbitrile.cpp | 29 +++++ cell.cpp | 2 +- fieldpattern.cpp | 256 +++++++++++++++++++++++++++++++++++++- geom-exp.cpp | 24 +++- reg3.cpp | 316 +++++++++++++++++++---------------------------- 5 files changed, 430 insertions(+), 197 deletions(-) diff --git a/arbitrile.cpp b/arbitrile.cpp index e7c24cda..8919e239 100644 --- a/arbitrile.cpp +++ b/arbitrile.cpp @@ -443,6 +443,35 @@ struct hrmap_arbi : hrmap { } } + transmatrix relative_matrix(heptagon *h2, heptagon *h1, const hyperpoint& hint) override { + if(gmatrix0.count(h2->c7) && gmatrix0.count(h1->c7)) + return inverse(gmatrix0[h1->c7]) * gmatrix0[h2->c7]; + transmatrix gm = Id, where = Id; + while(h1 != h2) { + for(int i=0; itype; i++) { + if(h1->move(i) == h2) { + return gm * adj(h1, i) * where; + } + } + if(h1->distance > h2->distance) { + for(int i=0; itype; i++) if(h1->move(i) && h1->move(i)->distance < h1->distance) { + gm = gm * adj(h1, i); + h1 = h1->move(i); + goto again; + } + } + else { + for(int i=0; itype; i++) if(h2->move(i) && h2->move(i)->distance < h2->distance) { + where = iadj(h2, 0) * where; + h2 = h2->move(i); + goto again; + } + } + again: ; + } + return gm * where; + } + transmatrix adj(cell *c, int dir) override { return adj(c->master, dir); } ld spin_angle(cell *c, int d) override { return SPIN_NOT_AVAILABLE; } diff --git a/cell.cpp b/cell.cpp index a76ff566..5ee179a4 100644 --- a/cell.cpp +++ b/cell.cpp @@ -983,7 +983,7 @@ EX int celldistance(cell *c1, cell *c2) { if(hybri) return hybrid::celldistance(c1, c2); #if CAP_FIELD - if(geometry == gFieldQuotient && !GOLDBERG) + if(geometry == gFieldQuotient && !GOLDBERG && WDIM == 2) return currfp.getdist(fieldpattern::fieldval(c1), fieldpattern::fieldval(c2)); #endif diff --git a/fieldpattern.cpp b/fieldpattern.cpp index 7e5f195b..27ea5c7c 100644 --- a/fieldpattern.cpp +++ b/fieldpattern.cpp @@ -29,7 +29,7 @@ struct fgeomextra { }; #endif -bool isprime(int n) { +EX bool isprime(int n) { for(int k=2; k generate_isometries(); bool check_order(matrix M, int req); + + unsigned compute_hash(); + + // general 4D + vector fullv; + + void add1(const matrix& M); + void add1(const matrix& M, const transmatrix& Full); + vector generate_isometries3(); + int solve3(); + void generate_all3(); }; #endif @@ -323,6 +337,166 @@ vector fpattern::generate_isometries() { return res; } +vector fpattern::generate_isometries3() { + + matrix T = Id; + int low = wsquare ? 1-Prime : 0; + vector res; + + auto colprod = [&] (int a, int b) { + return add(add(mul(T[0][a], T[0][b]), mul(T[1][a], T[1][b])), sub(mul(T[2][a], T[2][b]), mul(T[3][a], T[3][b]))); + }; + + auto rowcol = [&] (int a, int b) { + return add(add(mul(T[a][0], T[0][b]), mul(T[a][1], T[1][b])), add(mul(T[a][2], T[2][b]), mul(T[a][3], T[3][b]))); + }; + + for(T[0][0]=low; T[0][0] hash_found; + +unsigned fpattern::compute_hash() { + unsigned hashv = 0; + int iR = matcode[R]; + int iP = matcode[P]; + int iX = matcode[X]; + for(int i=0; i fails(N); + + vector possible_P, possible_X, possible_R; + + for(auto& M: iso3) { + if(check_order(M, 2)) + possible_X.push_back(M); + if(check_order(M, reg3::r_order)) + possible_R.push_back(M); + } + for(auto& M: iso4) + if(check_order(M, 2)) + possible_P.push_back(M); + + DEBB(DF_FIELD, ("field = ", Field, " #P = ", isize(possible_P), " #X = ", isize(possible_X), " #R = ", isize(possible_R), " r_order = ", reg3::r_order, " xp_order = ", reg3::xp_order)); + + for(auto& xX: possible_X) + for(auto& xP: possible_P) if(check_order(mmul(xP, xX), reg3::xp_order)) + for(auto& xR: possible_R) if(check_order(mmul(xR, xX), reg3::rx_order)) { // if(xR[0][0] == 1 && xR[0][1] == 0) { + auto by = [&] (char ch) -> matrix& { return ch == 'X' ? xX : ch == 'R' ? xR : xP; }; + for(int i=0; i g(geometry, gSpace435); + return current_quotient_field; + if(geometry == gSpace535) { + // 120 cells, hash = 9EF7A9C4 static fpattern fp(5); return fp; } + if(geometry == gSpace534) { + // 260 cells, hash = 72414D0C (not 0C62E214) + static fpattern fp(0); + if(fp.Prime) return fp; + fp.Prime = 5; fp.force_hash = 0x72414D0C; fp.solve(); + return fp; + } + if(geometry == gSpace435) { + // 650 cells, hash = EB201050 + static fpattern fp(0); + if(fp.Prime) return fp; + fp.Prime = 5; fp.force_hash = 0x72414D0C; fp.solve(); + return fp; + } + if(geometry == gSpace336) { + // 672 cells in E3F6B7BC + // 672 cells in 885F1184 + // 9408 cells in C4089F34 + static fpattern fp(0); + if(fp.Prime) return fp; + fp.Prime = 7; fp.force_hash = 0xE3F6B7BCu; fp.solve(); + return fp; + } + if(geometry == gSpace344) { + // 600 cells in 558C8ED0 + // 2400 cells in AF042EA8 + // 2600 cells in D26948E0 + // 2600 cells in EC29DCEC + static fpattern fp(0); + if(fp.Prime) return fp; + fp.Prime = 5; fp.force_hash = 0x558C8ED0u; fp.solve(); + return fp; + // 4900 cells in CDCC7860 (7) + } + if(geometry == gSpace536) { + static fpattern fp(0); + if(fp.Prime) return fp; + // 130 cells in 3BA5C5A4 + // 260 cells in 9FDE7B38 + fp.Prime = 7; fp.force_hash = 0x9FDE7B38u; fp.solve(); + return fp; + } + if(WDIM == 3) { + static fpattern fp(0); + if(fp.Prime) return fp; + for(int p=2; p<8; p++) { fp.Prime = p; if(!fp.solve()) break; } + DEBB(DF_FIELD, ("set prime = ", fp.Prime)); + return fp; + } if(S7 == 8 && S3 == 3) { static fpattern fp(17); return fp; @@ -900,6 +1134,20 @@ EX void enableFieldChange() { fieldpattern::current_quotient_field.init(gxcur.primes[gxcur.current_prime_id].p); } +EX void field_from_current() { + auto& go = ginf[geometry]; + dynamicval g(geometry, gFieldQuotient); + auto& gg = ginf[geometry]; + gg.sides = go.sides; + gg.vertex = go.vertex; + gg.distlimit = go.distlimit; + gg.tiling_name = go.tiling_name; + gg.flags = go.flags | qANYQ | qFIELD | qBOUNDED; + gg.g = go.g; + gg.default_variation = go.default_variation; + fieldpattern::quotient_field_changed = true; + } + EX } #define currfp fieldpattern::getcurrfp() diff --git a/geom-exp.cpp b/geom-exp.cpp index 9e75b21e..55d164da 100644 --- a/geom-exp.cpp +++ b/geom-exp.cpp @@ -316,6 +316,8 @@ void set_or_configure_geometry(eGeometry g) { bool same_tiling(eGeometry g2) { if(g2 == gCrystal) return S3 == 4; + if(g2 == gFieldQuotient && hyperbolic && standard_tiling()) + return true; if(g2 == gFieldQuotient && geometry != gFieldQuotient) { int ce = 0; for(auto& ge: fieldpattern::fgeomextras) { @@ -456,7 +458,15 @@ EX void select_quotient_screen() { "no quotient", g == geometry, key++); dialog::add_action([g] { - if(g == gFieldQuotient) + if(g == gFieldQuotient && WDIM == 3) { + stop_game(); + fieldpattern::field_from_current(); + set_geometry(gFieldQuotient); + for(int p=2;; p++) { currfp.Prime = p; currfp.force_hash = 0; if(!currfp.solve()) break; } + println(hlog, "set prime = ", currfp.Prime); + start_game(); + } + else if(g == gFieldQuotient) pushScreen(showQuotientConfig); else if(g == gCrystal) pushScreen(crystal::show); @@ -900,6 +910,14 @@ int read_geom_args() { enableFieldChange(); set_geometry(gFieldQuotient); } + else if(argis("-to-fq")) { + shift(); unsigned hash = arghex(); + stop_game_and_switch_mode(rg::nothing); + fieldpattern::field_from_current(); + set_geometry(gFieldQuotient); + for(int p=2;; p++) { currfp.Prime = p; currfp.force_hash = hash; if(!currfp.solve()) break; } + println(hlog, "set prime = ", currfp.Prime); + } else if(argis("-cs")) { shift(); cheat(); fieldpattern::matrix M = currfp.strtomatrix(args()); @@ -940,6 +958,10 @@ int read_geom_args() { fieldpattern::info(); exit(0); } + else if(argis("-fi-geo")) { + fieldpattern::info(); + exit(0); + } else if(argis("-qs")) { cheat(); shift(); currfp.qpaths.push_back(args()); diff --git a/reg3.cpp b/reg3.cpp index f9b2429c..87aeab3e 100644 --- a/reg3.cpp +++ b/reg3.cpp @@ -32,7 +32,7 @@ EX namespace reg3 { EX int face; EX vector cellshape; - vector vertices_only; + EX vector vertices_only; EX transmatrix spins[12], adjmoves[12]; @@ -237,6 +237,8 @@ EX namespace reg3 { void initialize(int cell_count); vector& allcells() override { return acells; } + + vector get_vertices(cell* c) override { return vertices_only; } }; #endif @@ -324,196 +326,37 @@ EX namespace reg3 { } } }; - - struct hrmap_field3 : hrmap_quotient3 { - - int mgmul(std::initializer_list v) { - int a = 0; - for(int b: v) a = a ? currfp_gmul(a, b) : b; - return a; - } - - vector fullmatrices; - - int P, R, X; - transmatrix full_P, full_R, full_X; - - vector field_adjmoves; - vector cyclers; - int perm_group; + + struct hrmap_field3 : reg3::hrmap_quotient3 { - vector cell_to_code; - vector code_to_cell; - - void seek(set& seen_matrices, set& seen_codes, const transmatrix& at, int ccode, const hyperpoint checker) { - if(hdist0(tC0(at)) > 4) return; - int b = bucketer(tC0(at)); - if(seen_matrices.count(b)) return; - seen_matrices.insert(b); - for(int a=0; a known(perm_group, false); - known[0] = true; - for(int a=0; a moveid(S7), movedir(lgr); + for(int s=0; s .1 && hdist(h, corner3) > .1 && abs(hdist(h, corner0)-hdist(corner0, corner1)) < .1) - cornerx = h; - DEBB(DF_FIELD, ("corner0 = ", corner0)); - DEBB(DF_FIELD, ("corner1 = ", corner1)); - DEBB(DF_FIELD, ("corner3 = ", corner3)); - DEBB(DF_FIELD, ("cornerx = ", cornerx)); - - transmatrix adj = Id, iadj = Id; - - geometry = g; - reg3::generate(); - - cyclers.clear(); - DEBB(DF_FIELD, ("S7 = ", S7)); - if(S7 == 12) { - - transmatrix resmatrix; - set_column(resmatrix, 0, corner0); - set_column(resmatrix, 1, corner1); - set_column(resmatrix, 2, corner3); - set_column(resmatrix, 3, cornerx); - - transmatrix transformer; - set_column(transformer, 0, C0); - set_column(transformer, 1, tC0(reg3::adjmoves[0])); - set_column(transformer, 2, tC0(reg3::adjmoves[1])); - set_column(transformer, 3, tC0(reg3::adjmoves[2])); - - transmatrix cav = resmatrix * inverse(transformer); - DEBB(DF_FIELD, ("cav = ", cav)); - DEBB(DF_FIELD, ("cav * C0 = ", cav * C0)); - - set seen_matrices; - set seen_codes; - seek(seen_matrices, seen_codes, Id, 0, corner0); - - for(int x: seen_codes) cyclers.push_back(x); - perm_group = isize(cyclers); - adj = cav; - iadj = inverse(cav); - } - else { - for(int i=0; imove(d) = allh[code_to_cell[tmul2]]; - allh[i]->c7->move(d) = allh[i]->move(d)->c7; - tmatrices[i].push_back(reg3::adjmoves[d] * iadj * fullmatrices[s] * adj); - found++; - } - } - if(found != 1) DEBB(DF_FIELD, ("bad found: ", i, "/", d, "/", found)); - // println(hlog, "tmatrix(",i,",",d,") = ", tmatrices[i][d]); - } - } - - DEBB(DF_FIELD, ("setting spin...")); - for(int i=0; imove(d)->move(e) == allh[i]) { - allh[i]->c.setspin(d, e, false); - allh[i]->c7->c.setspin(d, e, false); - } - - DEBB(DF_FIELD, ("creating patterns...")); + } create_patterns(); } @@ -529,8 +372,9 @@ EX namespace reg3 { void create_patterns() { + auto& f = currfp; // change the geometry to make sure that the correct celldistance is used - dynamicval g(geometry, S7 == 12 ? gField534 : gField435); + dynamicval g(geometry, gFieldQuotient); // also, strafe needs currentmap dynamicval c(currentmap, this); @@ -572,7 +416,7 @@ EX namespace reg3 { for(int i=0; imaster->fieldval)) ok = false; } @@ -595,17 +439,13 @@ EX namespace reg3 { int u = 0; for(int a=0; a<5; a++) { for(int o: plane_indices) { - int j = code_to_cell[currfp_gmul(u, cell_to_code[o])]; + int j = currfp_gmul(u, o * f.local_group) / f.local_group; allcells()[j]->master->zebraval |= 2; } u = currfp_gmul(u, gpow); } } } - - vector get_vertices(cell* c) override { - return vertices_only; - } }; /** homology cover of the Seifert-Weber space */ @@ -770,7 +610,7 @@ EX namespace reg3 { quotient_map = new seifert_weber::hrmap_seifert_cover; h.zebraval = quotient_map->allh[0]->zebraval; } - else if(hyperbolic && !(cgflags & qIDEAL)) { + else if(hyperbolic) { quotient_map = new hrmap_field3; h.zebraval = quotient_map->allh[0]->zebraval; } @@ -1085,6 +925,7 @@ EX bool pseudohept(cell *c) { return hr::celldistance(c, currentmap->gamestart()) & 1; if(geometry == gCrystal344 || geometry == gCrystal534 || geometry == gSeifertCover) return false; + if(quotient) return false; /* added */ if(hyperbolic) { heptagon *h = m->reg_gmatrix[c->master].first; return (h->zebraval == 1) && (h->distance & 1); @@ -1225,6 +1066,99 @@ EX cellwalker strafe(cellwalker cw, int j) { println(hlog, "incorrect strafe"); exit(1); } + +EX vector > rels; +EX int xp_order, r_order, rx_order; + +EX transmatrix full_X, full_R, full_P; +geometry_information *for_cgi; + +EX int matrix_order(const transmatrix A) { + transmatrix T = A; + int res = 1; + while(!eqmatrix(T, Id)) { + res++; T = T * A; + } + return res; + } + +EX void construct_relations() { + if(for_cgi == &cgi) return; + for_cgi = &cgi; + rels.clear(); + + reg3::generate(); + reg3::generate_cellrotations(); + vector all; + + vector formulas; + + formulas.push_back(""); + + all.push_back(Id); + hyperpoint v = reg3::cellshape[0]; + auto add = [&] (transmatrix T) { + for(int i=0; i 5) return; + for(hyperpoint h: reg3::cellshape) if(hdist(T * h, v) < 1e-4) goto ok; + return; + ok: + int id = add(T); + // println(hlog, p, " x ", (s0+c), " = ", id); + + if(id >= isize(formulas)) formulas.push_back(formulas[p] + c); + else if(id == 0) println(hlog, "reached identity: ", formulas[p]+c); + else if(formulas[p][0] != formulas[id][0]) + rels.emplace_back(formulas[p] + c, formulas[id]); + }; + + for(int i=0; i