#include "triangle.h" #include "linalg.h" #include "mat.h" #include //#define MAX_ELEMENTS 2800000 //#define MAX_ELEMENTS 720000 #define MAX_ELEMENTS 14000 //#define DRAW_PICTURE 1 void continued_fraction_approximation(mpq_t out, double in, int level) { mpq_t tmp; if(in < 0) { mpq_init(tmp); mpq_set_ui(tmp, 0, 1); continued_fraction_approximation(out, -in, level); mpq_sub(out, tmp, out); mpq_clear(tmp); return; } if(level == 0) { mpq_set_si(out, (signed long int)round(in), 1); // floor(in) } else { continued_fraction_approximation(out, 1/(in - floor(in)), level - 1); mpq_init(tmp); mpq_set_ui(tmp, 1, 1); mpq_div(out, tmp, out); // out -> 1/out mpq_set_si(tmp, (signed long int)in, 1); // floor(in) mpq_add(out, out, tmp); mpq_clear(tmp); } } void quartic(mpq_t out, mpq_t in, int a, int b, int c, int d, int e) { mpq_t tmp; mpq_init(tmp); mpq_set_si(out, a, 1); mpq_mul(out, out, in); mpq_set_si(tmp, b, 1); mpq_add(out, out, tmp); mpq_mul(out, out, in); mpq_set_si(tmp, c, 1); mpq_add(out, out, tmp); mpq_mul(out, out, in); mpq_set_si(tmp, d, 1); mpq_add(out, out, tmp); mpq_mul(out, out, in); mpq_set_si(tmp, e, 1); mpq_add(out, out, tmp); mpq_clear(tmp); } void initialize_triangle_generators(mat_workspace *ws, mat *gen, mpq_t s, mpq_t t) { mpq_set_ui(*mat_ref(gen[0], 0, 0), 0, 1); mpq_set_ui(*mat_ref(gen[0], 0, 1), 0, 1); mpq_set_ui(*mat_ref(gen[0], 0, 2), 1, 1); mpq_set_ui(*mat_ref(gen[0], 1, 0), 1, 1); mpq_set_ui(*mat_ref(gen[0], 1, 1), 0, 1); mpq_set_ui(*mat_ref(gen[0], 1, 2), 0, 1); mpq_set_ui(*mat_ref(gen[0], 2, 0), 0, 1); mpq_set_ui(*mat_ref(gen[0], 2, 1), 1, 1); mpq_set_ui(*mat_ref(gen[0], 2, 2), 0, 1); mpq_set_ui(*mat_ref(gen[1], 0, 0), 1, 1); mpq_set_ui(*mat_ref(gen[1], 1, 0), 0, 1); mpq_set_ui(*mat_ref(gen[1], 2, 0), 0, 1); quartic(*mat_ref(gen[1], 0, 1), t, 0, 0, 1, -1, 2); quartic(*mat_ref(gen[1], 1, 1), t, 0, 0, -1, 2, -2); quartic(*mat_ref(gen[1], 2, 1), t, 0, 0, 1, -3, 3); quartic(*mat_ref(gen[1], 0, 2), t, 0, 0, 1, 0, 3); quartic(*mat_ref(gen[1], 1, 2), t, 0, 0, -1, 1, -1); quartic(*mat_ref(gen[1], 2, 2), t, 0, 0, 1, -2, 1); mat_pseudoinverse(ws, gen[3], gen[0]); // p^{-1} mat_pseudoinverse(ws, gen[4], gen[1]); // q^{-1} mat_multiply(ws, gen[2], gen[4], gen[3]); // r = q^{-1}p^{-1} mat_pseudoinverse(ws, gen[5], gen[2]); // mat_print(gen[0]); // mat_print(gen[1]); // mat_print(gen[2]); // mat_print(gen[3]); // mat_print(gen[4]); // mat_print(gen[5]); } char *print_word(groupelement_t *g, char *str) { int i = g->length - 1; str[g->length] = 0; while(g->parent) { str[i--] = 'a' + g->letter; g = g->parent; } return str; } void enumerate(groupelement_t *group, mat *matrices, mpq_t s, mpq_t t) { mat_workspace *ws; mat tmp; mat gen[6]; char buf[100], buf2[100], buf3[100]; // allocate stuff ws = mat_workspace_init(3); for(int i = 0; i < 6; i++) mat_init(gen[i], 3); mat_init(tmp, 3); initialize_triangle_generators(ws, gen, s, t); mat_identity(matrices[0]); for(int i = 1; i < MAX_ELEMENTS; i++) { if(group[i].length % 2 != 0) continue; if(!group[i].inverse) continue; int parent = group[i].parent->id; int grandparent = group[i].parent->parent->id; int letter; if(group[parent].letter == 1 && group[i].letter == 2) letter = 0; // p = bc else if(group[parent].letter == 2 && group[i].letter == 0) letter = 1; // q = ca else if(group[parent].letter == 0 && group[i].letter == 1) letter = 2; // r = ab if(group[parent].letter == 2 && group[i].letter == 1) letter = 3; // p^{-1} = cb else if(group[parent].letter == 0 && group[i].letter == 2) letter = 4; // q^{-1} = ac else if(group[parent].letter == 1 && group[i].letter == 0) letter = 5; // r^{-1} = ba mat_multiply(ws, matrices[i], matrices[grandparent], gen[letter]); } // free stuff for(int i = 0; i < 6; i++) mat_clear(gen[i]); mat_clear(tmp); mat_workspace_clear(ws); } void output_invariants(groupelement_t *group, mat *matrices, mpq_t s, mpq_t t) { mpq_t tr, trinv; char buf[100]; mpq_inits(tr, trinv, NULL); for(int i = 0; i < MAX_ELEMENTS; i++) { if(group[i].length % 2 != 0 || !group[i].inverse) continue; mat_trace(tr, matrices[i]); mat_trace(trinv, matrices[group[i].inverse->id]); gmp_printf("%d %d %s %Qd %Qd %f %f\n", i, group[i].length, print_word(&group[i], buf), tr, trinv, log(mpq_get_d(tr)), log(mpq_get_d(trinv))); } mpq_clears(tr, trinv, NULL); } double max_slope(groupelement_t *group, mat *matrices, mpq_t s, mpq_t t, int *index) { double max = 0; double slope; mpq_t tr, trinv; char buf[100]; mpq_inits(tr, trinv, NULL); for(int i = 0; i < MAX_ELEMENTS; i++) { if(group[i].length % 2 != 0 || !group[i].inverse) continue; mat_trace(tr, matrices[i]); mat_trace(trinv, matrices[group[i].inverse->id]); slope = log(mpq_get_d(trinv))/log(mpq_get_d(tr)); if(slope > max) { *index = i; max = slope; } } mpq_clears(tr, trinv, NULL); return max; } int main(int argc, char *argv[]) { mpq_t s, t, tmp; mpz_t accuracy; double t_; mat *matrices; groupelement_t *group; int index; mpq_inits(s, t, tmp, NULL); mpz_init(accuracy); group = malloc(MAX_ELEMENTS*sizeof(groupelement_t)); matrices = malloc(MAX_ELEMENTS*sizeof(mat)); for(int i = 0; i < MAX_ELEMENTS; i++) mat_init(matrices[i], 3); // mpq_set_str(t, argv[1], 10); mpz_set_ui(accuracy, 100); for(int i = 0; ; i++) { mpq_set(t, tmp); continued_fraction_approximation(tmp, atof(argv[1]), i); if(mpz_cmp(mpq_numref(tmp),accuracy) > 0 && mpz_cmp(mpq_denref(tmp),accuracy) > 0) break; } mpq_canonicalize(t); gmp_fprintf(stdout, "\"t = %Qd = %.3f\"\n", mpq_get_d(t), t); if(argc > 2 && strcmp(argv[2],"p") == 0) { gmp_fprintf(stdout, "%Qd\n", t); return 0; } generate_triangle_group(group, MAX_ELEMENTS, 3, 3, 4); // for(int i = 0; i < 10; i++) { // mpq_set_ui(t,100+i,100); // mpq_canonicalize(t); enumerate(group, matrices, s, t); //printf("%f %f\n", mpq_get_d(t), max_slope(group, matrices, s, t, &index)); output_invariants(group, matrices, s, t); // } for(int i = 0; i < MAX_ELEMENTS; i++) mat_clear(matrices[i]); free(matrices); free(group); mpq_clears(s, t, tmp, NULL); mpz_clear(accuracy); }