remove irrelevant files
This commit is contained in:
parent
ac80bc9f3f
commit
575c310cd3
@ -1,335 +0,0 @@
|
|||||||
#include "enumerate_triangle_group.h"
|
|
||||||
#include "linalg.h"
|
|
||||||
|
|
||||||
int solve_characteristic_polynomial(mps_context *solv, mps_monomial_poly *poly, mpq_t tr, mpq_t trinv, double *eigenvalues)
|
|
||||||
{
|
|
||||||
mpq_t coeff1, coeff2, zero;
|
|
||||||
cplx_t *roots;
|
|
||||||
double radii[3];
|
|
||||||
double *radii_p[3];
|
|
||||||
mps_boolean errors;
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
mpq_inits(coeff1, coeff2, zero, NULL);
|
|
||||||
mpq_set(coeff1, trinv);
|
|
||||||
mpq_sub(coeff2, zero, tr);
|
|
||||||
|
|
||||||
mps_monomial_poly_set_coefficient_int(solv, poly, 0, -1, 0);
|
|
||||||
mps_monomial_poly_set_coefficient_q(solv, poly, 1, coeff1, zero);
|
|
||||||
mps_monomial_poly_set_coefficient_q(solv, poly, 2, coeff2, zero);
|
|
||||||
mps_monomial_poly_set_coefficient_int(solv, poly, 3, 1, 0);
|
|
||||||
|
|
||||||
mps_context_set_input_poly(solv, (mps_polynomial*)poly);
|
|
||||||
mps_mpsolve(solv);
|
|
||||||
|
|
||||||
roots = cplx_valloc(3);
|
|
||||||
for(int i = 0; i < 3; i++)
|
|
||||||
radii_p[i] = &(radii[i]);
|
|
||||||
mps_context_get_roots_d(solv, &roots, radii_p);
|
|
||||||
errors = mps_context_has_errors(solv);
|
|
||||||
|
|
||||||
if(errors) {
|
|
||||||
result = 1;
|
|
||||||
} else {
|
|
||||||
for(int i = 0; i < 3; i++) {
|
|
||||||
eigenvalues[i] = cplx_Re(roots[i]);
|
|
||||||
if(fabs(cplx_Im(roots[i])) > radii[i]) // non-real root
|
|
||||||
result = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cplx_vfree(roots);
|
|
||||||
mpq_clears(coeff1, coeff2, zero, NULL);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(NUMBER out, NUMBER in, int a, int b, int c, int d, int e)
|
|
||||||
{
|
|
||||||
NUMBER tmp;
|
|
||||||
INIT(tmp, GETTYPE(in));
|
|
||||||
|
|
||||||
SET_INT(out, a);
|
|
||||||
|
|
||||||
MUL(out, out, in);
|
|
||||||
SET_INT(tmp, b);
|
|
||||||
ADD(out, out, tmp);
|
|
||||||
|
|
||||||
MUL(out, out, in);
|
|
||||||
SET_INT(tmp, c);
|
|
||||||
ADD(out, out, tmp);
|
|
||||||
|
|
||||||
MUL(out, out, in);
|
|
||||||
SET_INT(tmp, d);
|
|
||||||
ADD(out, out, tmp);
|
|
||||||
|
|
||||||
MUL(out, out, in);
|
|
||||||
SET_INT(tmp, e);
|
|
||||||
ADD(out, out, tmp);
|
|
||||||
|
|
||||||
CLEAR(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// discriminant of the polynomial z^3 - x z^2 + y z - 1
|
|
||||||
// that is the function x^2 y^2 - 4 x^3 - 4 y^3 - 27 + 18 xy
|
|
||||||
void discriminant(NUMBER out, NUMBER x, NUMBER y)
|
|
||||||
{
|
|
||||||
TYPE type = GETTYPE(out);
|
|
||||||
NUMBER x2, x3, y2, y3, tmp;
|
|
||||||
INIT(x2, type);INIT(x3, type);INIT(y2, type);INIT(y3, type);INIT(tmp, type);
|
|
||||||
|
|
||||||
MUL(x2, x, x);
|
|
||||||
MUL(x3, x2, x);
|
|
||||||
MUL(y2, y, y);
|
|
||||||
MUL(y3, y2, y);
|
|
||||||
|
|
||||||
MUL(out, x2, y2);
|
|
||||||
|
|
||||||
SET_INT(tmp, -4);
|
|
||||||
MUL(tmp, tmp, x3);
|
|
||||||
ADD(out, out, tmp);
|
|
||||||
|
|
||||||
SET_INT(tmp, -4);
|
|
||||||
MUL(tmp, tmp, y3);
|
|
||||||
ADD(out, out, tmp);
|
|
||||||
|
|
||||||
SET_INT(tmp, -27);
|
|
||||||
ADD(out, out, tmp);
|
|
||||||
|
|
||||||
SET_INT(tmp, 18);
|
|
||||||
MUL(tmp, tmp, x);
|
|
||||||
MUL(tmp, tmp, y);
|
|
||||||
ADD(out, out, tmp);
|
|
||||||
|
|
||||||
CLEAR(x2);CLEAR(x3);CLEAR(y2);CLEAR(y3);CLEAR(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void generators_triangle_rotation_generic(mat *gen, NUMBER rho1, NUMBER rho2, NUMBER rho3, mpq_t s, mpq_t q)
|
|
||||||
{
|
|
||||||
mat_workspace *ws;
|
|
||||||
mat r1,r2,r3;
|
|
||||||
NUMBER b1,c1,a2,c2,a3,b3;
|
|
||||||
TYPE type = GETTYPE(rho1);
|
|
||||||
mpq_t sinv, qinv;
|
|
||||||
|
|
||||||
ws = mat_workspace_init(3, type);
|
|
||||||
INIT(b1, type);INIT(c1, type);INIT(a2, type);INIT(c2, type);INIT(a3, type);INIT(b3, type);
|
|
||||||
mpq_init(sinv);
|
|
||||||
mpq_init(qinv);
|
|
||||||
mat_init(r1, 3, type);
|
|
||||||
mat_init(r2, 3, type);
|
|
||||||
mat_init(r3, 3, type);
|
|
||||||
|
|
||||||
// sinv = s^{-1}
|
|
||||||
mpq_inv(sinv, s);
|
|
||||||
mpq_inv(qinv, q);
|
|
||||||
|
|
||||||
// c1 = rho2 q, a2 = rho3 q, b3 = rho1 q, b1 = c2 = a3 = 1/q
|
|
||||||
SET_Q(c1, q);
|
|
||||||
SET_Q(a2, q);
|
|
||||||
SET_Q(b3, q);
|
|
||||||
MUL(c1, c1, rho2);
|
|
||||||
MUL(a2, a2, rho3);
|
|
||||||
MUL(b3, b3, rho1);
|
|
||||||
SET_INT(b1, 1);
|
|
||||||
SET_INT(c2, 1);
|
|
||||||
SET_INT(a3, 1);
|
|
||||||
SET_Q(b1, qinv);
|
|
||||||
SET_Q(c2, qinv);
|
|
||||||
SET_Q(a3, qinv);
|
|
||||||
|
|
||||||
mat_zero(r1);
|
|
||||||
mat_zero(r2);
|
|
||||||
mat_zero(r3);
|
|
||||||
SET_INT(*mat_ref(r1, 0, 0), -1);
|
|
||||||
SET_INT(*mat_ref(r1, 1, 1), 1);
|
|
||||||
SET_INT(*mat_ref(r1, 2, 2), 1);
|
|
||||||
SET_INT(*mat_ref(r2, 0, 0), 1);
|
|
||||||
SET_INT(*mat_ref(r2, 1, 1), -1);
|
|
||||||
SET_INT(*mat_ref(r2, 2, 2), 1);
|
|
||||||
SET_INT(*mat_ref(r3, 0, 0), 1);
|
|
||||||
SET_INT(*mat_ref(r3, 1, 1), 1);
|
|
||||||
SET_INT(*mat_ref(r3, 2, 2), -1);
|
|
||||||
|
|
||||||
SET(*mat_ref(r1, 1, 0), b1);
|
|
||||||
SET(*mat_ref(r1, 2, 0), c1);
|
|
||||||
SET(*mat_ref(r2, 0, 1), a2);
|
|
||||||
SET(*mat_ref(r2, 2, 1), c2);
|
|
||||||
SET(*mat_ref(r3, 0, 2), a3);
|
|
||||||
SET(*mat_ref(r3, 1, 2), b3);
|
|
||||||
|
|
||||||
mat_zero(gen[0]);
|
|
||||||
mat_zero(gen[1]);
|
|
||||||
mat_zero(gen[2]);
|
|
||||||
|
|
||||||
// gen[0] = diag(1,s^{-1},s)
|
|
||||||
SET_INT(*mat_ref(gen[0], 0, 0), 1);
|
|
||||||
SET_Q (*mat_ref(gen[0], 1, 1), sinv);
|
|
||||||
SET_Q (*mat_ref(gen[0], 2, 2), s);
|
|
||||||
|
|
||||||
// gen[1] = diag(s,1,s^{-1})
|
|
||||||
SET_Q (*mat_ref(gen[1], 0, 0), s);
|
|
||||||
SET_INT(*mat_ref(gen[1], 1, 1), 1);
|
|
||||||
SET_Q (*mat_ref(gen[1], 2, 2), sinv);
|
|
||||||
|
|
||||||
// gen[2] = diag(s^{-1},s,1)
|
|
||||||
SET_Q (*mat_ref(gen[2], 0, 0), sinv);
|
|
||||||
SET_Q (*mat_ref(gen[2], 1, 1), s);
|
|
||||||
SET_INT(*mat_ref(gen[2], 2, 2), 1);
|
|
||||||
|
|
||||||
// gen[0] = r2 * gen[0] * r3
|
|
||||||
// gen[1] = r3 * gen[1] * r1
|
|
||||||
// gen[2] = r1 * gen[2] * r2
|
|
||||||
mat_multiply(ws, gen[0], r2, gen[0]);
|
|
||||||
mat_multiply(ws, gen[0], gen[0], r3);
|
|
||||||
mat_multiply(ws, gen[1], r3, gen[1]);
|
|
||||||
mat_multiply(ws, gen[1], gen[1], r1);
|
|
||||||
mat_multiply(ws, gen[2], r1, gen[2]);
|
|
||||||
mat_multiply(ws, gen[2], gen[2], r2);
|
|
||||||
|
|
||||||
// gen[3] = gen[0]^{-1}
|
|
||||||
// gen[4] = gen[1]^{-1}
|
|
||||||
// gen[5] = gen[2]^{-1}
|
|
||||||
mat_pseudoinverse(ws, gen[3], gen[0]);
|
|
||||||
mat_pseudoinverse(ws, gen[4], gen[1]);
|
|
||||||
mat_pseudoinverse(ws, gen[5], gen[2]);
|
|
||||||
|
|
||||||
mat_workspace_clear(ws);
|
|
||||||
CLEAR(b1);CLEAR(c1);CLEAR(a2);CLEAR(c2);CLEAR(a3);CLEAR(b3);
|
|
||||||
mpq_clear(sinv);
|
|
||||||
mpq_clear(qinv);
|
|
||||||
mat_clear(r1);
|
|
||||||
mat_clear(r2);
|
|
||||||
mat_clear(r3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef QEXT_TRIVIAL
|
|
||||||
// p1,p2,p3 are only allowed to be 2,3,4,6
|
|
||||||
void generators_triangle_rotation_2346_rational(mat *gen, int p1, int p2, int p3, mpq_t s, mpq_t q)
|
|
||||||
{
|
|
||||||
mpq_t rho1, rho2, rho3;
|
|
||||||
mpq_inits(rho1,rho2,rho3,NULL);
|
|
||||||
|
|
||||||
// rho_i = s^2 + 2s cos(2 pi / p_i) + 1
|
|
||||||
// coefficient 2 is the value for p=infinity, not sure if that would even work
|
|
||||||
quartic(rho1, s, 0, 0, 1, p1 == 2 ? -2 : p1 == 3 ? -1 : p1 == 4 ? 0 : p1 == 6 ? 1 : 2, 1);
|
|
||||||
quartic(rho2, s, 0, 0, 1, p2 == 2 ? -2 : p2 == 3 ? -1 : p2 == 4 ? 0 : p2 == 6 ? 1 : 2, 1);
|
|
||||||
quartic(rho3, s, 0, 0, 1, p3 == 2 ? -2 : p3 == 3 ? -1 : p3 == 4 ? 0 : p3 == 6 ? 1 : 2, 1);
|
|
||||||
|
|
||||||
generators_triangle_rotation_generic(gen, rho1, rho2, rho3, s, q);
|
|
||||||
|
|
||||||
mpq_clears(rho1,rho2,rho3,NULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef QEXT
|
|
||||||
void generators_triangle_rotation_555_barbot(mat *gen, mpq_t s_, mpq_t q_)
|
|
||||||
{
|
|
||||||
NUMBER rho, c, one, s;
|
|
||||||
INIT(rho, QT_SQRT5);INIT(c, QT_SQRT5);INIT(one, QT_SQRT5);INIT(s, QT_SQRT5);
|
|
||||||
|
|
||||||
// c = - (1+sqrt(5))/2
|
|
||||||
mpq_set_si(c->a[0], -1, 2);
|
|
||||||
mpq_set_si(c->a[1], -1, 2);
|
|
||||||
SET_ONE(one);
|
|
||||||
|
|
||||||
SET_Q(s, s_);
|
|
||||||
|
|
||||||
// rho = s^2 + cs + 1
|
|
||||||
SET(rho, one);
|
|
||||||
MUL(rho, rho, s);
|
|
||||||
ADD(rho, rho, c);
|
|
||||||
MUL(rho, rho, s);
|
|
||||||
ADD(rho, rho, one);
|
|
||||||
|
|
||||||
generators_triangle_rotation_generic(gen, rho, rho, rho, s_, q_);
|
|
||||||
|
|
||||||
CLEAR(rho);CLEAR(c);CLEAR(one);CLEAR(s);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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_triangle_rotation_subgroup(group_t *group, mat *gen, mat *matrices)
|
|
||||||
{
|
|
||||||
mat_workspace *ws;
|
|
||||||
mat tmp;
|
|
||||||
char buf[100], buf2[100], buf3[100];
|
|
||||||
|
|
||||||
// allocate stuff
|
|
||||||
TYPE type = GETTYPE(gen[0]->x[0]);
|
|
||||||
ws = mat_workspace_init(3, type);
|
|
||||||
mat_init(tmp, 3, type);
|
|
||||||
|
|
||||||
// initialize_triangle_generators(ws, gen, p1, p2, p3, s, q);
|
|
||||||
|
|
||||||
mat_identity(matrices[0]);
|
|
||||||
for(int i = 1; i < group->size; i++) {
|
|
||||||
if(group->elements[i].length % 2 != 0)
|
|
||||||
continue;
|
|
||||||
if(!group->elements[i].inverse)
|
|
||||||
continue;
|
|
||||||
if(!group->elements[i].need_to_compute)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int parent = group->elements[i].parent->id;
|
|
||||||
int grandparent = group->elements[i].parent->parent->id;
|
|
||||||
int letter;
|
|
||||||
|
|
||||||
if(group->elements[parent].letter == 1 && group->elements[i].letter == 2)
|
|
||||||
letter = 0; // p = bc
|
|
||||||
else if(group->elements[parent].letter == 2 && group->elements[i].letter == 0)
|
|
||||||
letter = 1; // q = ca
|
|
||||||
else if(group->elements[parent].letter == 0 && group->elements[i].letter == 1)
|
|
||||||
letter = 2; // r = ab
|
|
||||||
if(group->elements[parent].letter == 2 && group->elements[i].letter == 1)
|
|
||||||
letter = 3; // p^{-1} = cb
|
|
||||||
else if(group->elements[parent].letter == 0 && group->elements[i].letter == 2)
|
|
||||||
letter = 4; // q^{-1} = ac
|
|
||||||
else if(group->elements[parent].letter == 1 && group->elements[i].letter == 0)
|
|
||||||
letter = 5; // r^{-1} = ba
|
|
||||||
|
|
||||||
mat_multiply(ws, matrices[i], matrices[grandparent], gen[letter]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// free stuff
|
|
||||||
mat_clear(tmp);
|
|
||||||
mat_workspace_clear(ws);
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
#ifndef ENUMERATE_TRIANGLE_GROUP_H
|
|
||||||
#define ENUMERATE_TRIANGLE_GROUP_H
|
|
||||||
|
|
||||||
#include "mat.h"
|
|
||||||
#include "coxeter.h"
|
|
||||||
|
|
||||||
#include <mps/mps.h>
|
|
||||||
|
|
||||||
// rational only functions
|
|
||||||
int solve_characteristic_polynomial(mps_context *solv, mps_monomial_poly *poly, mpq_t tr, mpq_t trinv, double *eigenvalues);
|
|
||||||
void continued_fraction_approximation(mpq_t out, double in, int level);
|
|
||||||
|
|
||||||
// generators
|
|
||||||
void generators_triangle_rotation_generic(mat *gen, NUMBER rho1, NUMBER rho2, NUMBER rho3, mpq_t s, mpq_t q);
|
|
||||||
|
|
||||||
#ifdef QEXT_TRIVIAL
|
|
||||||
void generators_triangle_rotation_2346_rational(mat *gen, int p1, int p2, int p3, mpq_t s, mpq_t q);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef QEXT
|
|
||||||
void generators_triangle_rotation_555_barbot(mat *gen, mpq_t s_, mpq_t q_);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// general functions
|
|
||||||
void quartic(NUMBER out, NUMBER in, int a, int b, int c, int d, int e);
|
|
||||||
void discriminant(NUMBER out, NUMBER x, NUMBER y);
|
|
||||||
char *print_word(groupelement_t *g, char *str);
|
|
||||||
void enumerate_triangle_rotation_subgroup(group_t *group, mat *gen, mat *matrices);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,471 +0,0 @@
|
|||||||
#include "coxeter.h"
|
|
||||||
#include "linalg.h"
|
|
||||||
#include "mat.h"
|
|
||||||
#include "enumerate_triangle_group.h"
|
|
||||||
#include "parallel.h"
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#define SWAP(t,x,y) do { t _tmp = (x); (x) = (y); (y) = _tmp; } while (0);
|
|
||||||
|
|
||||||
//#define DEBUG(msg, ...) fprintf(stderr, "[%003d%10.3f] " msg, mpi_rank(0), runtime(), ##__VA_ARGS__)
|
|
||||||
#define DEBUG(msg, ...)
|
|
||||||
#define INFO(msg, ...) fprintf(stderr, "[%003d%10.3f] " msg, mpi_rank(0), runtime(), ##__VA_ARGS__)
|
|
||||||
|
|
||||||
struct result {
|
|
||||||
int id;
|
|
||||||
mpq_t tr;
|
|
||||||
mpq_t trinv;
|
|
||||||
double x;
|
|
||||||
double y;
|
|
||||||
double slope;
|
|
||||||
};
|
|
||||||
|
|
||||||
// we want as much as possible to be node data, except if it is only known to the main node
|
|
||||||
// (command line arguments) or should only be computed once (id list)
|
|
||||||
|
|
||||||
struct global_data {
|
|
||||||
// command line arguments
|
|
||||||
unsigned int nmax;
|
|
||||||
unsigned int p1, p2, p3;
|
|
||||||
unsigned int sstart, send, sdenom;
|
|
||||||
unsigned int qstart, qend, qdenom;
|
|
||||||
|
|
||||||
unsigned int *id_list;
|
|
||||||
unsigned int id_list_length;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct node_data {
|
|
||||||
group_t *group;
|
|
||||||
mat* matrices;
|
|
||||||
struct result *invariants;
|
|
||||||
struct result **distinct_invariants;
|
|
||||||
int distinct_invariants_length;
|
|
||||||
mps_context *solver;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct input_data {
|
|
||||||
unsigned int snum, sden;
|
|
||||||
unsigned int qnum, qden;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct output_data {
|
|
||||||
int max_slope_id;
|
|
||||||
double max_slope;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int compare_result(const void *a_, const void *b_)
|
|
||||||
{
|
|
||||||
int d = 0;
|
|
||||||
|
|
||||||
struct result **a = (struct result **)a_;
|
|
||||||
struct result **b = (struct result **)b_;
|
|
||||||
|
|
||||||
d = mpq_cmp((*a)->tr,(*b)->tr);
|
|
||||||
if(d == 0) {
|
|
||||||
d = mpq_cmp((*a)->trinv, (*b)->trinv);
|
|
||||||
}
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_result_by_id(const void *a_, const void *b_)
|
|
||||||
{
|
|
||||||
int d = 0;
|
|
||||||
|
|
||||||
struct result **a = (struct result **)a_;
|
|
||||||
struct result **b = (struct result **)b_;
|
|
||||||
|
|
||||||
return (*a)->id - (*b)->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_result_by_tr_trinv_id(const void *a_, const void *b_)
|
|
||||||
{
|
|
||||||
int d = 0;
|
|
||||||
|
|
||||||
struct result **a = (struct result **)a_;
|
|
||||||
struct result **b = (struct result **)b_;
|
|
||||||
|
|
||||||
d = mpq_cmp((*a)->tr,(*b)->tr);
|
|
||||||
if(d == 0) {
|
|
||||||
d = mpq_cmp((*a)->trinv, (*b)->trinv);
|
|
||||||
if(d == 0) {
|
|
||||||
d = (*b)->id - (*a)->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_result_by_slope(const void *a_, const void *b_)
|
|
||||||
{
|
|
||||||
int d = 0;
|
|
||||||
|
|
||||||
struct result **a = (struct result **)a_;
|
|
||||||
struct result **b = (struct result **)b_;
|
|
||||||
|
|
||||||
double slopea = (*a)->x / (*a)->y;
|
|
||||||
double slopeb = (*b)->x / (*b)->y;
|
|
||||||
|
|
||||||
return slopea > slopeb ? -1 : slopea < slopeb ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int compute_invariants(group_t *group, mat *matrices, struct result **invariants, int *n, int unique)
|
|
||||||
{
|
|
||||||
mpq_t tmp;
|
|
||||||
mps_context *solver;
|
|
||||||
mps_monomial_poly *poly;
|
|
||||||
int index;
|
|
||||||
int ntraces = *n, nuniq;
|
|
||||||
int retval;
|
|
||||||
double evs[3];
|
|
||||||
char buf[100];
|
|
||||||
|
|
||||||
// DEBUG("Compute traces\n");
|
|
||||||
for(int i = 0; i < ntraces; i++) {
|
|
||||||
int id = invariants[i]->id;
|
|
||||||
int invid = group->elements[id].inverse->id;
|
|
||||||
mat_trace(invariants[i]->tr, matrices[id]);
|
|
||||||
mat_trace(invariants[i]->trinv, matrices[invid]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!unique)
|
|
||||||
nuniq = ntraces;
|
|
||||||
else {
|
|
||||||
// DEBUG("Get unique traces\n");
|
|
||||||
qsort(invariants, ntraces, sizeof(struct result*), compare_result);
|
|
||||||
|
|
||||||
nuniq = 0;
|
|
||||||
for(int i = 0; i < ntraces; i++) {
|
|
||||||
if(i == 0 || compare_result(&invariants[i], &invariants[nuniq-1]) != 0) {
|
|
||||||
invariants[nuniq] = invariants[i];
|
|
||||||
nuniq++;
|
|
||||||
} else {
|
|
||||||
int oldlength = group->elements[invariants[nuniq-1]->id].length;
|
|
||||||
int newlength = group->elements[invariants[i]->id].length;
|
|
||||||
if(newlength < oldlength)
|
|
||||||
invariants[nuniq-1]->id = invariants[i]->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("Solve characteristic polynomials\n");
|
|
||||||
solver = mps_context_new();
|
|
||||||
poly = mps_monomial_poly_new(solver, 3);
|
|
||||||
mps_context_set_output_prec(solver, 20); // relative precision
|
|
||||||
mps_context_set_output_goal(solver, MPS_OUTPUT_GOAL_APPROXIMATE);
|
|
||||||
|
|
||||||
for(int i = 0; i < nuniq; i++) {
|
|
||||||
retval = solve_characteristic_polynomial(solver, poly, invariants[i]->tr, invariants[i]->trinv, evs);
|
|
||||||
|
|
||||||
if(retval == 1) {
|
|
||||||
fprintf(stderr, "Error! Could not solve polynomial.\n");
|
|
||||||
continue;
|
|
||||||
} else if(retval == 2) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fabs(evs[0]) < fabs(evs[1]))
|
|
||||||
SWAP(double, evs[0], evs[1]);
|
|
||||||
if(fabs(evs[1]) < fabs(evs[2]))
|
|
||||||
SWAP(double, evs[1], evs[2]);
|
|
||||||
if(fabs(evs[0]) < fabs(evs[1]))
|
|
||||||
SWAP(double, evs[0], evs[1]);
|
|
||||||
|
|
||||||
double x = log(fabs(evs[0]));
|
|
||||||
double y = -log(fabs(evs[2]));
|
|
||||||
|
|
||||||
invariants[i]->x = x;
|
|
||||||
invariants[i]->y = y;
|
|
||||||
invariants[i]->slope = y/x;
|
|
||||||
}
|
|
||||||
mps_context_free(solver);
|
|
||||||
|
|
||||||
qsort(invariants, nuniq, sizeof(struct result*), compare_result_by_id);
|
|
||||||
|
|
||||||
*n = nuniq;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long check_memory_usage(mat *matrices, int n)
|
|
||||||
{
|
|
||||||
mpq_t x;
|
|
||||||
long total;
|
|
||||||
|
|
||||||
for(int i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
LOOP(j,3) LOOP(k,3) {
|
|
||||||
total += mpq_numref(M(matrices[i], j, k))->_mp_size;
|
|
||||||
total += mpq_denref(M(matrices[i], j, k))->_mp_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void destroy_node(const void *_g, void *_n)
|
|
||||||
{
|
|
||||||
struct global_data *g = (struct global_data *)_g;
|
|
||||||
struct node_data *n = (struct node_data *)_n;
|
|
||||||
|
|
||||||
for(int i = 0; i < g->nmax; i++) {
|
|
||||||
mpq_clear(n->invariants[i].tr);
|
|
||||||
mpq_clear(n->invariants[i].trinv);
|
|
||||||
}
|
|
||||||
free(n->invariants);
|
|
||||||
free(n->distinct_invariants);
|
|
||||||
for(int i = 0; i < g->nmax; i++)
|
|
||||||
mat_clear(n->matrices[i]);
|
|
||||||
free(n->matrices);
|
|
||||||
coxeter_clear(n->group);
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_node(const void *_g, void *_n)
|
|
||||||
{
|
|
||||||
struct global_data *g = (struct global_data *)_g;
|
|
||||||
struct node_data *n = (struct node_data *)_n;
|
|
||||||
|
|
||||||
DEBUG("Allocate\n");
|
|
||||||
g->id_list = (int*)(g+1); // pointers get scrambled by transmission, reconstruct
|
|
||||||
n->matrices = malloc(g->nmax*sizeof(mat));
|
|
||||||
for(int i = 0; i < g->nmax; i++)
|
|
||||||
mat_init(n->matrices[i], 3);
|
|
||||||
n->invariants = malloc(g->nmax*sizeof(struct result));
|
|
||||||
n->distinct_invariants = malloc(g->nmax*sizeof(struct result)); // we won't need that many, but just in case
|
|
||||||
for(int i = 0; i < g->nmax; i++) {
|
|
||||||
mpq_init(n->invariants[i].tr);
|
|
||||||
mpq_init(n->invariants[i].trinv);
|
|
||||||
n->invariants[i].id = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// order of the triangle reflection generators: a, b, c
|
|
||||||
// order of the rotation orders: bc, ac, ab
|
|
||||||
DEBUG("Generate group\n");
|
|
||||||
n->group = coxeter_init_triangle(g->p1, g->p2, g->p3, g->nmax);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int process_output(group_t *group, mat *matrices, struct result **invariants, int invariants_length, struct output_data *out)
|
|
||||||
{
|
|
||||||
out->max_slope = 0;
|
|
||||||
for(int i = 0; i < invariants_length; i++) {
|
|
||||||
double x = invariants[i]->x;
|
|
||||||
double y = invariants[i]->y;
|
|
||||||
|
|
||||||
if(y/x > out->max_slope + 1e-12 && (x > 0.1 || y > 0.1)) {
|
|
||||||
out->max_slope_id = invariants[i]->id;
|
|
||||||
out->max_slope = y/x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int do_computation(const void *_g, void *_n, const void *_in, void *_out)
|
|
||||||
{
|
|
||||||
struct global_data *g = (struct global_data *)_g;
|
|
||||||
struct node_data *n = (struct node_data *)_n;
|
|
||||||
struct input_data *in = (struct input_data *)_in;
|
|
||||||
struct output_data *out = (struct output_data *)_out;
|
|
||||||
|
|
||||||
mpq_t s, q;
|
|
||||||
|
|
||||||
mpq_inits(s, q, NULL);
|
|
||||||
mpq_set_ui(s, in->snum, in->sden);
|
|
||||||
mpq_set_ui(q, in->qnum, in->qden);
|
|
||||||
|
|
||||||
INFO("Computing max slope element for s = %d/%d and q = %d/%d.\n",
|
|
||||||
in->snum, in->sden,
|
|
||||||
in->qnum, in->qden);
|
|
||||||
|
|
||||||
for(int i = 0; i < n->group->size; i++)
|
|
||||||
n->group->elements[i].need_to_compute = 0;
|
|
||||||
n->group->elements[0].need_to_compute = 1;
|
|
||||||
|
|
||||||
int needed_elements = 1;
|
|
||||||
for(int i = 0; i < g->id_list_length; i++)
|
|
||||||
{
|
|
||||||
int id = g->id_list[i];
|
|
||||||
n->distinct_invariants[i] = &n->invariants[id];
|
|
||||||
groupelement_t *cur = &n->group->elements[id];
|
|
||||||
while(cur->need_to_compute == 0) {
|
|
||||||
cur->need_to_compute = 1;
|
|
||||||
needed_elements++;
|
|
||||||
cur = cur->parent->parent; // also need to compute its even-length ancestors
|
|
||||||
}
|
|
||||||
cur = n->group->elements[id].inverse;
|
|
||||||
while(cur->need_to_compute == 0) {
|
|
||||||
cur->need_to_compute = 1;
|
|
||||||
needed_elements++;
|
|
||||||
cur = cur->parent->parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n->distinct_invariants_length = g->id_list_length;
|
|
||||||
|
|
||||||
DEBUG("Need to compute %d elements to get %d traces up to reflection length %d\n",
|
|
||||||
needed_elements, g->id_list_length, n->group->elements[n->group->size-1].length);
|
|
||||||
|
|
||||||
DEBUG("Compute matrices\n");
|
|
||||||
enumerate(n->group, n->matrices, g->p1, g->p2, g->p3, s, q);
|
|
||||||
|
|
||||||
DEBUG("Compute invariants\n");
|
|
||||||
compute_invariants(
|
|
||||||
n->group, n->matrices,
|
|
||||||
n->distinct_invariants, &n->distinct_invariants_length, 1);
|
|
||||||
|
|
||||||
DEBUG("Find max slopes\n");
|
|
||||||
process_output(n->group, n->matrices, n->distinct_invariants, n->distinct_invariants_length, out);
|
|
||||||
|
|
||||||
mpq_clears(s, q, NULL);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
char buf[100];
|
|
||||||
char buf2[100];
|
|
||||||
struct global_data *g;
|
|
||||||
struct node_data n;
|
|
||||||
|
|
||||||
start_timer();
|
|
||||||
|
|
||||||
// parse command line arguments
|
|
||||||
if(argc < 11) {
|
|
||||||
fprintf(stderr, "Usage: %s <N> <p1> <p2> <p3> <s start> <s end> <s denom> <q start> <q end> <q denom> [restart]\n", argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
int nmax = atoi(argv[1]);
|
|
||||||
g = (struct global_data*)malloc(sizeof(struct global_data) + nmax*sizeof(int));
|
|
||||||
g->id_list = (int*)(g+1);
|
|
||||||
g->nmax = nmax;
|
|
||||||
g->p1 = atoi(argv[2]);
|
|
||||||
g->p2 = atoi(argv[3]);
|
|
||||||
g->p3 = atoi(argv[4]);
|
|
||||||
g->sstart = atoi(argv[5]);
|
|
||||||
g->send = atoi(argv[6]);
|
|
||||||
g->sdenom = atoi(argv[7]);
|
|
||||||
g->qstart = atoi(argv[8]);
|
|
||||||
g->qend = atoi(argv[9]);
|
|
||||||
g->qdenom = atoi(argv[10]);
|
|
||||||
|
|
||||||
// initialize
|
|
||||||
parallel_context *ctx = parallel_init();
|
|
||||||
parallel_set_datasize_and_callbacks(ctx, init_node, do_computation, destroy_node,
|
|
||||||
sizeof(struct global_data) + g->nmax*sizeof(int),
|
|
||||||
sizeof(struct node_data),
|
|
||||||
sizeof(struct input_data),
|
|
||||||
sizeof(struct output_data));
|
|
||||||
if(ctx->mpi_mode == 1 && ctx->rank != 0) {
|
|
||||||
// worker mode
|
|
||||||
parallel_work(ctx);
|
|
||||||
parallel_destroy(ctx);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
init_node(g, &n);
|
|
||||||
|
|
||||||
// use very generic values for the pilot run unless sstart=send and qstart=qend
|
|
||||||
struct input_data pilot_input;
|
|
||||||
struct output_data pilot_output;
|
|
||||||
if(g->sstart == g->send && g->qstart == g->qend) {
|
|
||||||
pilot_input.snum = g->sstart;
|
|
||||||
pilot_input.sden = g->sdenom;
|
|
||||||
pilot_input.qnum = g->qstart;
|
|
||||||
pilot_input.qden = g->qdenom;
|
|
||||||
DEBUG("Single run for s = %d/%d, q = %d/%d\n", g->sstart, g->sdenom, g->qstart, g->qdenom);
|
|
||||||
} else {
|
|
||||||
pilot_input.snum = 4;
|
|
||||||
pilot_input.sden = 100;
|
|
||||||
pilot_input.qnum = 7;
|
|
||||||
pilot_input.qden = 100;
|
|
||||||
DEBUG("Initial run for s = %d/%d, q = %d/%d\n", 4, 100, 7, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
g->id_list_length = 0;
|
|
||||||
for(int i = 0; i < n.group->size; i++)
|
|
||||||
if(n.group->elements[i].length % 2 == 0 && n.group->elements[i].inverse)
|
|
||||||
g->id_list[g->id_list_length++] = i;
|
|
||||||
|
|
||||||
do_computation(g, &n, &pilot_input, &pilot_output);
|
|
||||||
|
|
||||||
for(int i = 0; i < n.distinct_invariants_length; i++)
|
|
||||||
g->id_list[i] = n.distinct_invariants[i]->id;
|
|
||||||
g->id_list_length = n.distinct_invariants_length;
|
|
||||||
|
|
||||||
if(g->sstart != g->send || g->qstart != g->qend) {
|
|
||||||
|
|
||||||
struct input_data *inputs = malloc((g->send - g->sstart + 1)*(g->qend - g->qstart + 1)*sizeof(struct input_data));
|
|
||||||
struct output_data *outputs = malloc((g->send - g->sstart + 1)*(g->qend - g->qstart + 1)*sizeof(struct input_data));
|
|
||||||
|
|
||||||
int njobs = 0;
|
|
||||||
for(int sloop = g->sstart; sloop <= g->send; sloop++) {
|
|
||||||
for(int qloop = g->qstart; qloop <= g->qend; qloop++) {
|
|
||||||
inputs[njobs].sden = g->sdenom;
|
|
||||||
inputs[njobs].qden = g->qdenom;
|
|
||||||
inputs[njobs].snum = sloop;
|
|
||||||
inputs[njobs].qnum = qloop;
|
|
||||||
njobs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(argc >= 12)
|
|
||||||
parallel_run(ctx, g, inputs, outputs, njobs, argv[11]);
|
|
||||||
else
|
|
||||||
parallel_run(ctx, g, inputs, outputs, njobs, NULL);
|
|
||||||
|
|
||||||
// DEBUG("Loop for s = %d/%d, q = %d/%d\n", sloop, g->sdenom, qloop, g->qdenom);
|
|
||||||
|
|
||||||
for(int i = 0; i < njobs; i++)
|
|
||||||
{
|
|
||||||
gmp_printf("%d/%d %d/%d %d %s %f\n",
|
|
||||||
inputs[i].snum, inputs[i].sden, inputs[i].qnum, inputs[i].qden,
|
|
||||||
outputs[i].max_slope_id,
|
|
||||||
print_word(&n.group->elements[outputs[i].max_slope_id], buf),
|
|
||||||
outputs[i].max_slope);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(inputs);
|
|
||||||
free(outputs);
|
|
||||||
} else {
|
|
||||||
// output
|
|
||||||
for(int i = 0; i < n.distinct_invariants_length; i++) {
|
|
||||||
// exclude tr = trinv = 2/1/0/-1/3
|
|
||||||
mpq_t tmp;
|
|
||||||
mpq_init(tmp);
|
|
||||||
mpq_set_si(tmp, 2, 1);
|
|
||||||
if(mpq_cmp(n.distinct_invariants[i]->tr, tmp) == 0 &&
|
|
||||||
mpq_cmp(n.distinct_invariants[i]->trinv, tmp) == 0)
|
|
||||||
continue;
|
|
||||||
mpq_set_si(tmp, 1, 1);
|
|
||||||
if(mpq_cmp(n.distinct_invariants[i]->tr, tmp) == 0 &&
|
|
||||||
mpq_cmp(n.distinct_invariants[i]->trinv, tmp) == 0)
|
|
||||||
continue;
|
|
||||||
mpq_set_si(tmp, 0, 1);
|
|
||||||
if(mpq_cmp(n.distinct_invariants[i]->tr, tmp) == 0 &&
|
|
||||||
mpq_cmp(n.distinct_invariants[i]->trinv, tmp) == 0)
|
|
||||||
continue;
|
|
||||||
mpq_set_si(tmp, -1, 1);
|
|
||||||
if(mpq_cmp(n.distinct_invariants[i]->tr, tmp) == 0 &&
|
|
||||||
mpq_cmp(n.distinct_invariants[i]->trinv, tmp) == 0)
|
|
||||||
continue;
|
|
||||||
mpq_set_si(tmp, 3, 1);
|
|
||||||
if(mpq_cmp(n.distinct_invariants[i]->tr, tmp) == 0 &&
|
|
||||||
mpq_cmp(n.distinct_invariants[i]->trinv, tmp) == 0)
|
|
||||||
continue;
|
|
||||||
mpq_clear(tmp);
|
|
||||||
|
|
||||||
double slope = n.distinct_invariants[i]->y/n.distinct_invariants[i]->x;
|
|
||||||
|
|
||||||
gmp_printf("%d %s %f\n",
|
|
||||||
n.distinct_invariants[i]->id,
|
|
||||||
print_word(&n.group->elements[n.distinct_invariants[i]->id], buf),
|
|
||||||
slope);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy_node(g, &n);
|
|
||||||
free(g);
|
|
||||||
parallel_destroy(ctx);
|
|
||||||
}
|
|
@ -1,559 +0,0 @@
|
|||||||
#include "coxeter.h"
|
|
||||||
#include "linalg.h"
|
|
||||||
#include "mat.h"
|
|
||||||
#include "enumerate_triangle_group.h"
|
|
||||||
#include "parallel.h"
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#define SWAP(t,x,y) do { t _tmp = (x); (x) = (y); (y) = _tmp; } while (0);
|
|
||||||
|
|
||||||
//#define DEBUG(msg, ...) fprintf(stderr, "[%003d%10.3f] " msg, mpi_rank(0), runtime(), ##__VA_ARGS__)
|
|
||||||
#define DEBUG(msg, ...)
|
|
||||||
#define INFO(msg, ...) fprintf(stderr, "[%003d%10.3f] " msg, mpi_rank(0), runtime(), ##__VA_ARGS__)
|
|
||||||
|
|
||||||
struct result {
|
|
||||||
int id;
|
|
||||||
NUMBER tr;
|
|
||||||
NUMBER trinv;
|
|
||||||
int disc_sign;
|
|
||||||
};
|
|
||||||
|
|
||||||
// we want as much as possible to be node data, except if it is only known to the main node
|
|
||||||
// (command line arguments) or should only be computed once (id list)
|
|
||||||
|
|
||||||
struct global_data {
|
|
||||||
// command line arguments
|
|
||||||
unsigned int nmax;
|
|
||||||
unsigned int p1, p2, p3;
|
|
||||||
unsigned int sstart, send, sdenom;
|
|
||||||
unsigned int qstart, qend, qdenom;
|
|
||||||
|
|
||||||
unsigned int *id_list;
|
|
||||||
unsigned int id_list_length;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct node_data {
|
|
||||||
group_t *group;
|
|
||||||
mat* matrices;
|
|
||||||
struct result *invariants;
|
|
||||||
struct result **distinct_invariants;
|
|
||||||
int distinct_invariants_length;
|
|
||||||
mps_context *solver;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct input_data {
|
|
||||||
unsigned int snum, sden;
|
|
||||||
unsigned int qnum, qden;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct output_data {
|
|
||||||
int n_non_loxodromic;
|
|
||||||
int min_wordlength;
|
|
||||||
int elements[10];
|
|
||||||
};
|
|
||||||
|
|
||||||
static int compare_result(const void *a_, const void *b_)
|
|
||||||
{
|
|
||||||
int d = 0;
|
|
||||||
|
|
||||||
struct result **a = (struct result **)a_;
|
|
||||||
struct result **b = (struct result **)b_;
|
|
||||||
|
|
||||||
d = CMP((*a)->tr,(*b)->tr);
|
|
||||||
if(d == 0) {
|
|
||||||
d = CMP((*a)->trinv, (*b)->trinv);
|
|
||||||
}
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_result_by_id(const void *a_, const void *b_)
|
|
||||||
{
|
|
||||||
int d = 0;
|
|
||||||
|
|
||||||
struct result **a = (struct result **)a_;
|
|
||||||
struct result **b = (struct result **)b_;
|
|
||||||
|
|
||||||
return (*a)->id - (*b)->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_result_by_tr_trinv_id(const void *a_, const void *b_)
|
|
||||||
{
|
|
||||||
int d = 0;
|
|
||||||
|
|
||||||
struct result **a = (struct result **)a_;
|
|
||||||
struct result **b = (struct result **)b_;
|
|
||||||
|
|
||||||
d = CMP((*a)->tr,(*b)->tr);
|
|
||||||
if(d == 0) {
|
|
||||||
d = CMP((*a)->trinv, (*b)->trinv);
|
|
||||||
if(d == 0) {
|
|
||||||
d = (*b)->id - (*a)->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
static int compare_result_by_slope(const void *a_, const void *b_)
|
|
||||||
{
|
|
||||||
int d = 0;
|
|
||||||
|
|
||||||
struct result **a = (struct result **)a_;
|
|
||||||
struct result **b = (struct result **)b_;
|
|
||||||
|
|
||||||
double slopea = (*a)->x / (*a)->y;
|
|
||||||
double slopeb = (*b)->x / (*b)->y;
|
|
||||||
|
|
||||||
return slopea > slopeb ? -1 : slopea < slopeb ? 1 : 0;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
int invariants_trace_loxodromic(group_t *group, mat *matrices, struct result **invariants, int *n, int unique)
|
|
||||||
{
|
|
||||||
int ntraces = *n, nuniq; // ntraces is the number of traces we are asked to compute, nuniq is the number of unique ones after we eliminate duplicates
|
|
||||||
|
|
||||||
// compute the traces
|
|
||||||
for(int i = 0; i < ntraces; i++) {
|
|
||||||
int id = invariants[i]->id;
|
|
||||||
int invid = group->elements[id].inverse->id;
|
|
||||||
mat_trace(invariants[i]->tr, matrices[id]);
|
|
||||||
mat_trace(invariants[i]->trinv, matrices[invid]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// throw out duplicates if unique == 1
|
|
||||||
if(!unique)
|
|
||||||
nuniq = ntraces;
|
|
||||||
else {
|
|
||||||
qsort(invariants, ntraces, sizeof(struct result*), compare_result);
|
|
||||||
|
|
||||||
nuniq = 0;
|
|
||||||
for(int i = 0; i < ntraces; i++) {
|
|
||||||
if(i == 0 || compare_result(&invariants[i], &invariants[nuniq-1]) != 0) {
|
|
||||||
invariants[nuniq] = invariants[i];
|
|
||||||
nuniq++;
|
|
||||||
} else {
|
|
||||||
int oldlength = group->elements[invariants[nuniq-1]->id].length;
|
|
||||||
int newlength = group->elements[invariants[i]->id].length;
|
|
||||||
if(newlength < oldlength)
|
|
||||||
invariants[nuniq-1]->id = invariants[i]->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if loxodromic
|
|
||||||
NUMBER disc, zero;
|
|
||||||
double disc_real;
|
|
||||||
INIT(disc, QT_SQRT5);
|
|
||||||
INIT(zero, QT_SQRT5);
|
|
||||||
SET_ZERO(zero);
|
|
||||||
for(int i = 0; i < nuniq; i++) {
|
|
||||||
discriminant(disc, invariants[i]->tr, invariants[i]->trinv);
|
|
||||||
disc_real = mpq_get_d(disc->a[0]) + sqrt(5)*mpq_get_d(disc->a[1]);
|
|
||||||
gmp_printf("%Qd %Qd %f\n", disc->a[0], disc->a[1], disc_real);
|
|
||||||
invariants[i]->disc_sign = disc_real > 0 ? 1 : disc_real < 0 ? -1 : 0;
|
|
||||||
}
|
|
||||||
CLEAR(disc);
|
|
||||||
CLEAR(zero);
|
|
||||||
|
|
||||||
// sort by ID again
|
|
||||||
qsort(invariants, nuniq, sizeof(struct result*), compare_result_by_id);
|
|
||||||
|
|
||||||
*n = nuniq;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
int invariants_trace_slope(group_t *group, mat *matrices, struct result **invariants, int *n, int unique)
|
|
||||||
{
|
|
||||||
mpq_t tmp;
|
|
||||||
mps_context *solver;
|
|
||||||
mps_monomial_poly *poly;
|
|
||||||
int index;
|
|
||||||
int ntraces = *n, nuniq;
|
|
||||||
int retval;
|
|
||||||
double evs[3];
|
|
||||||
char buf[100];
|
|
||||||
|
|
||||||
// DEBUG("Compute traces\n");
|
|
||||||
for(int i = 0; i < ntraces; i++) {
|
|
||||||
int id = invariants[i]->id;
|
|
||||||
int invid = group->elements[id].inverse->id;
|
|
||||||
mat_trace(invariants[i]->tr, matrices[id]);
|
|
||||||
mat_trace(invariants[i]->trinv, matrices[invid]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!unique)
|
|
||||||
nuniq = ntraces;
|
|
||||||
else {
|
|
||||||
// DEBUG("Get unique traces\n");
|
|
||||||
qsort(invariants, ntraces, sizeof(struct result*), compare_result);
|
|
||||||
|
|
||||||
nuniq = 0;
|
|
||||||
for(int i = 0; i < ntraces; i++) {
|
|
||||||
if(i == 0 || compare_result(&invariants[i], &invariants[nuniq-1]) != 0) {
|
|
||||||
invariants[nuniq] = invariants[i];
|
|
||||||
nuniq++;
|
|
||||||
} else {
|
|
||||||
int oldlength = group->elements[invariants[nuniq-1]->id].length;
|
|
||||||
int newlength = group->elements[invariants[i]->id].length;
|
|
||||||
if(newlength < oldlength)
|
|
||||||
invariants[nuniq-1]->id = invariants[i]->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("Solve characteristic polynomials\n");
|
|
||||||
solver = mps_context_new();
|
|
||||||
poly = mps_monomial_poly_new(solver, 3);
|
|
||||||
mps_context_set_output_prec(solver, 20); // relative precision
|
|
||||||
mps_context_set_output_goal(solver, MPS_OUTPUT_GOAL_APPROXIMATE);
|
|
||||||
|
|
||||||
for(int i = 0; i < nuniq; i++) {
|
|
||||||
retval = solve_characteristic_polynomial(solver, poly, invariants[i]->tr, invariants[i]->trinv, evs);
|
|
||||||
|
|
||||||
if(retval == 1) {
|
|
||||||
fprintf(stderr, "Error! Could not solve polynomial.\n");
|
|
||||||
continue;
|
|
||||||
} else if(retval == 2) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fabs(evs[0]) < fabs(evs[1]))
|
|
||||||
SWAP(double, evs[0], evs[1]);
|
|
||||||
if(fabs(evs[1]) < fabs(evs[2]))
|
|
||||||
SWAP(double, evs[1], evs[2]);
|
|
||||||
if(fabs(evs[0]) < fabs(evs[1]))
|
|
||||||
SWAP(double, evs[0], evs[1]);
|
|
||||||
|
|
||||||
double x = log(fabs(evs[0]));
|
|
||||||
double y = -log(fabs(evs[2]));
|
|
||||||
|
|
||||||
invariants[i]->x = x;
|
|
||||||
invariants[i]->y = y;
|
|
||||||
invariants[i]->slope = y/x;
|
|
||||||
}
|
|
||||||
mps_context_free(solver);
|
|
||||||
|
|
||||||
qsort(invariants, nuniq, sizeof(struct result*), compare_result_by_id);
|
|
||||||
|
|
||||||
*n = nuniq;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
long check_memory_usage(mat *matrices, int n)
|
|
||||||
{
|
|
||||||
mpq_t x;
|
|
||||||
long total;
|
|
||||||
|
|
||||||
for(int i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
LOOP(j,3) LOOP(k,3) {
|
|
||||||
total += mpq_numref(M(matrices[i], j, k))->_mp_size;
|
|
||||||
total += mpq_denref(M(matrices[i], j, k))->_mp_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
void destroy_node(const void *_g, void *_n)
|
|
||||||
{
|
|
||||||
struct global_data *g = (struct global_data *)_g;
|
|
||||||
struct node_data *n = (struct node_data *)_n;
|
|
||||||
|
|
||||||
for(int i = 0; i < g->nmax; i++) {
|
|
||||||
CLEAR(n->invariants[i].tr);
|
|
||||||
CLEAR(n->invariants[i].trinv);
|
|
||||||
}
|
|
||||||
free(n->invariants);
|
|
||||||
free(n->distinct_invariants);
|
|
||||||
for(int i = 0; i < g->nmax; i++)
|
|
||||||
mat_clear(n->matrices[i]);
|
|
||||||
free(n->matrices);
|
|
||||||
coxeter_clear(n->group);
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_node(const void *_g, void *_n)
|
|
||||||
{
|
|
||||||
struct global_data *g = (struct global_data *)_g;
|
|
||||||
struct node_data *n = (struct node_data *)_n;
|
|
||||||
|
|
||||||
DEBUG("Allocate\n");
|
|
||||||
g->id_list = (int*)(g+1); // pointers get scrambled by transmission, reconstruct
|
|
||||||
n->matrices = malloc(g->nmax*sizeof(mat));
|
|
||||||
for(int i = 0; i < g->nmax; i++)
|
|
||||||
mat_init(n->matrices[i], 3, QT_SQRT5);
|
|
||||||
n->invariants = malloc(g->nmax*sizeof(struct result));
|
|
||||||
n->distinct_invariants = malloc(g->nmax*sizeof(struct result)); // we won't need that many, but just in case
|
|
||||||
for(int i = 0; i < g->nmax; i++) {
|
|
||||||
INIT(n->invariants[i].tr, QT_SQRT5);
|
|
||||||
INIT(n->invariants[i].trinv, QT_SQRT5);
|
|
||||||
n->invariants[i].id = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// order of the triangle reflection generators: a, b, c
|
|
||||||
// order of the rotation orders: bc, ac, ab
|
|
||||||
DEBUG("Generate group\n");
|
|
||||||
n->group = coxeter_init_triangle(g->p1, g->p2, g->p3, g->nmax);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int process_output(group_t *group, mat *matrices, struct result **invariants, int invariants_length, struct output_data *out)
|
|
||||||
{
|
|
||||||
out->n_non_loxodromic = 0;
|
|
||||||
out->min_wordlength = INT_MAX;
|
|
||||||
for(int i = 0; i < invariants_length; i++) {
|
|
||||||
if(invariants[i]->disc_sign <= 0 && invariants[i]->id != 0 && invariants[i]->id != 4 && invariants[i]->id != 22) {
|
|
||||||
if(out->n_non_loxodromic < 10)
|
|
||||||
out->elements[out->n_non_loxodromic] = invariants[i]->id;
|
|
||||||
out->n_non_loxodromic++;
|
|
||||||
if(group->elements[invariants[i]->id].length < out->min_wordlength)
|
|
||||||
out->min_wordlength = group->elements[invariants[i]->id].length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int do_computation(const void *_g, void *_n, const void *_in, void *_out)
|
|
||||||
{
|
|
||||||
struct global_data *g = (struct global_data *)_g;
|
|
||||||
struct node_data *n = (struct node_data *)_n;
|
|
||||||
struct input_data *in = (struct input_data *)_in;
|
|
||||||
struct output_data *out = (struct output_data *)_out;
|
|
||||||
|
|
||||||
mpq_t s, q;
|
|
||||||
|
|
||||||
mpq_inits(s, q, NULL);
|
|
||||||
mpq_set_ui(s, in->snum, in->sden);
|
|
||||||
mpq_set_ui(q, in->qnum, in->qden);
|
|
||||||
|
|
||||||
INFO("Computing represention with s = %d/%d and q = %d/%d.\n",
|
|
||||||
in->snum, in->sden,
|
|
||||||
in->qnum, in->qden);
|
|
||||||
|
|
||||||
// we need to compute all the elements pointed to in id_list, and all their suffixes or prefixes
|
|
||||||
// I can imagine a smarter way of doing this which checks if there is a shorter route to the element
|
|
||||||
for(int i = 0; i < n->group->size; i++)
|
|
||||||
n->group->elements[i].need_to_compute = 0;
|
|
||||||
n->group->elements[0].need_to_compute = 1;
|
|
||||||
|
|
||||||
int needed_elements = 1;
|
|
||||||
for(int i = 0; i < g->id_list_length; i++)
|
|
||||||
{
|
|
||||||
int id = g->id_list[i];
|
|
||||||
n->distinct_invariants[i] = &n->invariants[id];
|
|
||||||
groupelement_t *cur = &n->group->elements[id];
|
|
||||||
while(cur->need_to_compute == 0) {
|
|
||||||
cur->need_to_compute = 1;
|
|
||||||
needed_elements++;
|
|
||||||
cur = cur->parent->parent; // also need to compute its even-length ancestors
|
|
||||||
}
|
|
||||||
cur = n->group->elements[id].inverse;
|
|
||||||
while(cur->need_to_compute == 0) {
|
|
||||||
cur->need_to_compute = 1;
|
|
||||||
needed_elements++;
|
|
||||||
cur = cur->parent->parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n->distinct_invariants_length = g->id_list_length;
|
|
||||||
|
|
||||||
DEBUG("Need to compute %d elements to get %d traces up to reflection length %d\n",
|
|
||||||
needed_elements, g->id_list_length, n->group->elements[n->group->size-1].length);
|
|
||||||
|
|
||||||
DEBUG("Compute matrices\n");
|
|
||||||
mat gen[6];
|
|
||||||
for(int i = 0; i < 6; i++)
|
|
||||||
mat_init(gen[i], 3, QT_SQRT5);
|
|
||||||
|
|
||||||
generators_triangle_rotation_555_barbot(gen, s, q);
|
|
||||||
enumerate_triangle_rotation_subgroup(n->group, gen, n->matrices);
|
|
||||||
|
|
||||||
for(int i = 0; i < 6; i++)
|
|
||||||
mat_clear(gen[i]);
|
|
||||||
|
|
||||||
DEBUG("Compute invariants\n");
|
|
||||||
invariants_trace_loxodromic(
|
|
||||||
n->group, n->matrices,
|
|
||||||
n->distinct_invariants, &n->distinct_invariants_length, 1);
|
|
||||||
|
|
||||||
// DEBUG("Find max slopes\n");
|
|
||||||
process_output(n->group, n->matrices, n->distinct_invariants, n->distinct_invariants_length, out);
|
|
||||||
|
|
||||||
mpq_clears(s, q, NULL);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
char buf[1000];
|
|
||||||
char buf2[1000];
|
|
||||||
char buf3[1000];
|
|
||||||
struct global_data *g;
|
|
||||||
struct node_data n;
|
|
||||||
|
|
||||||
start_timer();
|
|
||||||
|
|
||||||
// parse command line arguments
|
|
||||||
if(argc < 11) {
|
|
||||||
fprintf(stderr, "Usage: %s <N> <p1> <p2> <p3> <s start> <s end> <s denom> <q start> <q end> <q denom> [restart]\n", argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
int nmax = atoi(argv[1]);
|
|
||||||
g = (struct global_data*)malloc(sizeof(struct global_data) + nmax*sizeof(int));
|
|
||||||
g->id_list = (int*)(g+1);
|
|
||||||
g->nmax = nmax;
|
|
||||||
g->p1 = atoi(argv[2]);
|
|
||||||
g->p2 = atoi(argv[3]);
|
|
||||||
g->p3 = atoi(argv[4]);
|
|
||||||
g->sstart = atoi(argv[5]);
|
|
||||||
g->send = atoi(argv[6]);
|
|
||||||
g->sdenom = atoi(argv[7]);
|
|
||||||
g->qstart = atoi(argv[8]);
|
|
||||||
g->qend = atoi(argv[9]);
|
|
||||||
g->qdenom = atoi(argv[10]);
|
|
||||||
|
|
||||||
// initialize
|
|
||||||
parallel_context *ctx = parallel_init();
|
|
||||||
parallel_set_datasize_and_callbacks(ctx, init_node, do_computation, destroy_node,
|
|
||||||
sizeof(struct global_data) + g->nmax*sizeof(int),
|
|
||||||
sizeof(struct node_data),
|
|
||||||
sizeof(struct input_data),
|
|
||||||
sizeof(struct output_data));
|
|
||||||
if(ctx->mpi_mode == 1 && ctx->rank != 0) {
|
|
||||||
// worker mode
|
|
||||||
parallel_work(ctx);
|
|
||||||
parallel_destroy(ctx);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
init_node(g, &n);
|
|
||||||
|
|
||||||
// use very generic values for the pilot run unless sstart=send and qstart=qend
|
|
||||||
struct input_data pilot_input;
|
|
||||||
struct output_data pilot_output;
|
|
||||||
if(g->sstart == g->send && g->qstart == g->qend) {
|
|
||||||
pilot_input.snum = g->sstart;
|
|
||||||
pilot_input.sden = g->sdenom;
|
|
||||||
pilot_input.qnum = g->qstart;
|
|
||||||
pilot_input.qden = g->qdenom;
|
|
||||||
DEBUG("Single run for s = %d/%d, q = %d/%d\n", g->sstart, g->sdenom, g->qstart, g->qdenom);
|
|
||||||
} else {
|
|
||||||
pilot_input.snum = 4;
|
|
||||||
pilot_input.sden = 100;
|
|
||||||
pilot_input.qnum = 7;
|
|
||||||
pilot_input.qden = 100;
|
|
||||||
DEBUG("Initial run for s = %d/%d, q = %d/%d\n", 4, 100, 7, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
g->id_list_length = 0;
|
|
||||||
for(int i = 0; i < n.group->size; i++)
|
|
||||||
if(n.group->elements[i].length % 2 == 0 && n.group->elements[i].inverse)
|
|
||||||
g->id_list[g->id_list_length++] = i;
|
|
||||||
|
|
||||||
do_computation(g, &n, &pilot_input, &pilot_output);
|
|
||||||
|
|
||||||
for(int i = 0; i < n.distinct_invariants_length; i++)
|
|
||||||
g->id_list[i] = n.distinct_invariants[i]->id;
|
|
||||||
g->id_list_length = n.distinct_invariants_length;
|
|
||||||
|
|
||||||
if(g->sstart != g->send || g->qstart != g->qend) {
|
|
||||||
|
|
||||||
struct input_data *inputs = malloc((g->send - g->sstart + 1)*(g->qend - g->qstart + 1)*sizeof(struct input_data));
|
|
||||||
struct output_data *outputs = malloc((g->send - g->sstart + 1)*(g->qend - g->qstart + 1)*sizeof(struct output_data));
|
|
||||||
|
|
||||||
int njobs = 0;
|
|
||||||
for(int sloop = g->sstart; sloop <= g->send; sloop++) {
|
|
||||||
for(int qloop = g->qstart; qloop <= g->qend; qloop++) {
|
|
||||||
inputs[njobs].sden = g->sdenom;
|
|
||||||
inputs[njobs].qden = g->qdenom;
|
|
||||||
inputs[njobs].snum = sloop;
|
|
||||||
inputs[njobs].qnum = qloop;
|
|
||||||
njobs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(argc >= 12)
|
|
||||||
parallel_run(ctx, g, inputs, outputs, njobs, argv[11]);
|
|
||||||
else
|
|
||||||
parallel_run(ctx, g, inputs, outputs, njobs, NULL);
|
|
||||||
|
|
||||||
// DEBUG("Loop for s = %d/%d, q = %d/%d\n", sloop, g->sdenom, qloop, g->qdenom);
|
|
||||||
|
|
||||||
for(int i = 0; i < njobs; i++)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
gmp_printf("%d/%d %d/%d %d %s %f\n",
|
|
||||||
inputs[i].snum, inputs[i].sden, inputs[i].qnum, inputs[i].qden,
|
|
||||||
outputs[i].max_slope_id,
|
|
||||||
print_word(&n.group->elements[outputs[i].max_slope_id], buf),
|
|
||||||
outputs[i].max_slope);
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
printf("%d/%d %d/%d %d %d",
|
|
||||||
inputs[i].snum, inputs[i].sden, inputs[i].qnum, inputs[i].qden,
|
|
||||||
outputs[i].n_non_loxodromic, outputs[i].min_wordlength);
|
|
||||||
for(int j = 0; j < 10 && j < outputs[i].n_non_loxodromic; j++)
|
|
||||||
printf(" %s", print_word(&n.group->elements[outputs[i].elements[j]], buf));
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
free(inputs);
|
|
||||||
free(outputs);
|
|
||||||
} else {
|
|
||||||
// output
|
|
||||||
for(int i = 0; i < n.distinct_invariants_length; i++) {
|
|
||||||
// exclude tr = trinv = 2/1/0/-1/3
|
|
||||||
|
|
||||||
/*
|
|
||||||
mpq_t tmp;
|
|
||||||
mpq_init(tmp);
|
|
||||||
mpq_set_si(tmp, 2, 1);
|
|
||||||
if(mpq_cmp(n.distinct_invariants[i]->tr, tmp) == 0 &&
|
|
||||||
mpq_cmp(n.distinct_invariants[i]->trinv, tmp) == 0)
|
|
||||||
continue;
|
|
||||||
mpq_set_si(tmp, 1, 1);
|
|
||||||
if(mpq_cmp(n.distinct_invariants[i]->tr, tmp) == 0 &&
|
|
||||||
mpq_cmp(n.distinct_invariants[i]->trinv, tmp) == 0)
|
|
||||||
continue;
|
|
||||||
mpq_set_si(tmp, 0, 1);
|
|
||||||
if(mpq_cmp(n.distinct_invariants[i]->tr, tmp) == 0 &&
|
|
||||||
mpq_cmp(n.distinct_invariants[i]->trinv, tmp) == 0)
|
|
||||||
continue;
|
|
||||||
mpq_set_si(tmp, -1, 1);
|
|
||||||
if(mpq_cmp(n.distinct_invariants[i]->tr, tmp) == 0 &&
|
|
||||||
mpq_cmp(n.distinct_invariants[i]->trinv, tmp) == 0)
|
|
||||||
continue;
|
|
||||||
mpq_set_si(tmp, 3, 1);
|
|
||||||
if(mpq_cmp(n.distinct_invariants[i]->tr, tmp) == 0 &&
|
|
||||||
mpq_cmp(n.distinct_invariants[i]->trinv, tmp) == 0)
|
|
||||||
continue;
|
|
||||||
mpq_clear(tmp);
|
|
||||||
*/
|
|
||||||
|
|
||||||
SNPRINT(buf, sizeof(buf), n.distinct_invariants[i]->tr);
|
|
||||||
SNPRINT(buf2, sizeof(buf2), n.distinct_invariants[i]->trinv);
|
|
||||||
printf("%d %s %d\n",
|
|
||||||
n.distinct_invariants[i]->id,
|
|
||||||
print_word(&n.group->elements[n.distinct_invariants[i]->id], buf3),
|
|
||||||
// mpq_get_d(n.distinct_invariants[i]->tr[0])+sqrt(5)*mpq_get_d(n.distinct_invariants[i]->tr[1]),
|
|
||||||
// mpq_get_d(n.distinct_invariants[i]->trinv[0])+sqrt(5)*mpq_get_d(n.distinct_invariants[i]->trinv[1]),
|
|
||||||
n.distinct_invariants[i]->disc_sign);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy_node(g, &n);
|
|
||||||
free(g);
|
|
||||||
parallel_destroy(ctx);
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
#a6cee3
|
|
||||||
#1f78b4
|
|
||||||
#b2df8a
|
|
||||||
#33a02c
|
|
||||||
#fb9a99
|
|
||||||
#e31a1c
|
|
||||||
#fdbf6f
|
|
||||||
#ff7f00
|
|
||||||
#cab2d6
|
|
||||||
#6a3d9a
|
|
||||||
#ffff99
|
|
||||||
#b15928
|
|
||||||
#ffff00
|
|
||||||
#00ffff
|
|
@ -1,6 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
convert -size 100x99 canvas:black combined.png
|
|
||||||
for a in partition_*.pnm; do
|
|
||||||
composite -compose plus combined.png $a combined.png
|
|
||||||
done
|
|
@ -1,69 +0,0 @@
|
|||||||
import Text.Printf
|
|
||||||
import System.Environment
|
|
||||||
import System.Process
|
|
||||||
import Data.List
|
|
||||||
|
|
||||||
wordlist = ["abacabacbabcbacbcacbac", "abacbabcbacbac", "abacbabcbacbcacbac", "abacbacbacbacbacbacbac", "abacbacbacbacbac", "abacbacbac", "bacabacbabcbacbcacbcac", "bacabacbabcbacbcac", "baca", "bacbabcbacbcac", "bacbacbacbacbacbacbcac", "bacbacbacbacbcac", "bacbacbcac", "bacbac"]
|
|
||||||
|
|
||||||
colors = [(0.651,0.808,0.890), (0.122,0.471,0.706), (0.698,0.875,0.541), (0.200,0.627,0.173), (0.984,0.604,0.600), (0.890,0.102,0.110), (0.992,0.749,0.435), (1.000,0.498,0.000), (0.792,0.698,0.839), (0.416,0.239,0.604), (1.000,1.000,0.600), (0.694,0.349,0.157), (1.000,1.000,0.000), (0.000,1.000,1.000)]
|
|
||||||
|
|
||||||
main = sequence $ zipWith (generatePicture "result_20210419_221603.out") wordlist colors
|
|
||||||
|
|
||||||
generatePicture :: String -> String -> (Double,Double,Double) -> IO ()
|
|
||||||
generatePicture datafile word color = do
|
|
||||||
file1 <- readFile datafile
|
|
||||||
file2 <- readProcess "../special_element" [word] ""
|
|
||||||
let values1 = map (normalize.read.(!!4).words) (lines file1) :: [Double]
|
|
||||||
let values2 = map (normalize.read.(!!3).words) (lines file2) :: [Double]
|
|
||||||
let diff = zipWith (-) values1 values2
|
|
||||||
writeFile (printf "partition_%s.pnm" word) $ drawGrayscalePicture color diff
|
|
||||||
printf "Wrote partition_%s.pnm\n" word
|
|
||||||
|
|
||||||
-- kind of a failed experiment
|
|
||||||
-- supersample (width, height) to (factor*width - factor + 1, factor*height - factor + 1)
|
|
||||||
-- supersample :: Int -> Int -> Int -> [Double] -> [Double]
|
|
||||||
-- supersample width height factor orig = [pix x y | x <- [0..(width-1)*factor], y <- [0..(height-1)*factor]]
|
|
||||||
-- where
|
|
||||||
-- pix x y = xl*yl*a + xl*yr*b + xr*yl*c + xr*yr*d
|
|
||||||
-- where
|
|
||||||
-- x_ = x`div`factor
|
|
||||||
-- y_ = y`div`factor
|
|
||||||
-- xr = fromIntegral (x`mod`factor)/fromIntegral factor :: Double
|
|
||||||
-- xl = 1 - xr :: Double
|
|
||||||
-- yr = fromIntegral (y`mod`factor)/fromIntegral factor :: Double
|
|
||||||
-- yl = 1 - yr :: Double
|
|
||||||
-- aoffset = x_*height + y_
|
|
||||||
-- boffset = x_*height + y_+1
|
|
||||||
-- coffset = (x_+1)*height + y_
|
|
||||||
-- doffset = (x_+1)*height + y_+1
|
|
||||||
-- a = orig!!aoffset
|
|
||||||
-- b = if boffset < width*height then orig!!boffset else 0
|
|
||||||
-- c = if coffset < width*height then orig!!coffset else 0
|
|
||||||
-- d = if doffset < width*height then orig!!doffset else 0
|
|
||||||
|
|
||||||
-- xl*yl*a + xl*yr*b + xr*yl*c + xr*yr*d
|
|
||||||
|
|
||||||
drawGrayscalePicture :: (Double,Double,Double) -> [Double] -> String
|
|
||||||
drawGrayscalePicture (r,g,b) values = drawPicture 100 99 $ map color values
|
|
||||||
where
|
|
||||||
color x = (round (255*r*colorscale x), round (255*g*colorscale x), round (255*b*colorscale x))
|
|
||||||
|
|
||||||
drawPicture :: Int -> Int -> [(Int,Int,Int)] -> String
|
|
||||||
drawPicture w h values = printf "P3\n%d %d\n255\n%s" w h pixels
|
|
||||||
where
|
|
||||||
pixels = concat [printf "%d %d %d\n" r g b | (r,g,b) <- values] :: String
|
|
||||||
|
|
||||||
normalize x = if x < 1 then 1/x else x
|
|
||||||
|
|
||||||
readDataFile :: String -> IO [(String,Double)]
|
|
||||||
readDataFile filename = do
|
|
||||||
f <- readFile filename
|
|
||||||
return $ map process $ map words $ lines f
|
|
||||||
where
|
|
||||||
process (x:y:_:_:z:rest) = (x++" "++y,read z)
|
|
||||||
normalize x = if x < 1 then 1/x else x
|
|
||||||
|
|
||||||
colorscale :: Double -> Double
|
|
||||||
colorscale x = if cs x < 0 then 1 else if cs x > 1 then 0 else 1 - cs x
|
|
||||||
where
|
|
||||||
cs x = 1e5*x
|
|
File diff suppressed because it is too large
Load Diff
@ -1,14 +0,0 @@
|
|||||||
-- resize and convert image with
|
|
||||||
-- convert max_slope_billiards.pnm -scale 3000x max_slope_billiards.png
|
|
||||||
|
|
||||||
import Text.Printf
|
|
||||||
|
|
||||||
colors = [(0.651,0.808,0.890), (0.122,0.471,0.706), (0.698,0.875,0.541), (0.200,0.627,0.173), (0.984,0.604,0.600), (0.890,0.102,0.110), (0.992,0.749,0.435), (1.000,0.498,0.000), (0.792,0.698,0.839), (0.416,0.239,0.604), (1.000,1.000,0.600), (0.694,0.349,0.157), (1.000,1.000,0.000), (0.000,1.000,1.000)]
|
|
||||||
col = map (\(r,g,b) -> (round $ r*255, round $ g*255, round $ b*255)) colors :: [(Int,Int,Int)]
|
|
||||||
|
|
||||||
main = do
|
|
||||||
foo <- readFile "max_slopes_billiard"
|
|
||||||
let dat = map (read.(!!2).words) $ lines foo :: [Int]
|
|
||||||
writeFile "max_slope_billiards.pnm" $ header ++ unlines [printf "%d %d %d" r g b | p <- dat, let (r,g,b) = col !! (p `mod` 14)]
|
|
||||||
where
|
|
||||||
header = "P3\n300\n123\n255\n"
|
|
@ -1,15 +0,0 @@
|
|||||||
if(!exists("index")) index = 50
|
|
||||||
|
|
||||||
set xrange [0:0.45]
|
|
||||||
set yrange [0:1]
|
|
||||||
set xyplane at 0
|
|
||||||
#plot "max_slopes_billiard" using 1:2:($3 - 10*floor($3/10)) w p pt 7 ps 1.1 lc palette t ""
|
|
||||||
plot "max_slopes_billiard" using 1:2:3 w p pt 7 ps 1.1 lc palette t ""
|
|
||||||
#splot "max_slopes_billiard" using 1:2:3 w p pt 7 ps 0.3 t ""
|
|
||||||
#plot "max_slopes_billiard" using 1:2:4 w p pt 7 ps 1.1 lc palette t ""
|
|
||||||
|
|
||||||
pause 10
|
|
||||||
#if(MOUSE_KEY == 60) index=index-1
|
|
||||||
#if(MOUSE_KEY == 62) index=index+1
|
|
||||||
#print MOUSE_KEY
|
|
||||||
reread
|
|
File diff suppressed because it is too large
Load Diff
@ -1,132 +0,0 @@
|
|||||||
bcabca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcbabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabcabcbabcabcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabcabcbabcabcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcbabcabcabcabcabcabcabcabcabcabcacbcabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcabcbabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabcacbcabcabcabcabcabcabcabcabcabcbabcabcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcbabcabcabcabcabcabcabcabcacbcabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcabcbabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcacbcabcabcabcabcabcabcabcbabcabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabcacbcabcabcabcabcabcabcabcbabcabcabcabcabcabcabcabacabcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcabacabcabcabcabcabcabcbabcabcabcabcabcabcacbcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcbabcabcabcabcabcabcacbcabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcbabcabcabcabcabcabcacbcabcabcabcabcabcabacabcabcabcabcabcabcbabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcbabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcabcbabcabcabcabcabcabacabcabcabcabcabcacbcabcabcabcabcabcbabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcacbcabcabcabcabcabcbabcabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcacbcabcabcabcabcabcbabcabcabcabcabcabacabcabcabcabcabaca
|
|
||||||
bcabcabcabcabcacbcabcabcabcabcabcbabcabcabcabcabcbabcabcabcabcabcabacabcabcabcabcabaca
|
|
||||||
bcabcabcabcabaca
|
|
||||||
bcabcabcabcabacabcabcabcabcbabcabcabcabcabcbabcabcabcabcacbcabcabcabcabcacbcabcabcabcabaca
|
|
||||||
bcabcabcabcabacabcabcabcabcbabcabcabcabcabcbabcabcabcabcacbcabcabcabcabaca
|
|
||||||
bcabcabcabcabacabcabcabcabcbabcabcabcabcacbcabcabcabcabaca
|
|
||||||
bcabcabcabcabacabcabcabcabcbabcabcabcabcacbcabcabcabcabacabcabcabcabcbabcabcabcabcacbcabcabcabcabaca
|
|
||||||
bcabcabcabcbabcabcabcabcacbcabcabcabcabaca
|
|
||||||
bcabcabcabcbabcabcabcabcacbcabcabcabcabacabcabcabcabcbabcabcabcabaca
|
|
||||||
bcabcabcabcbabcabcabcabcacbcabcabcabcabacabcabcabcacbcabcabcabcabacabcabcabcabcbabcabcabcabaca
|
|
||||||
bcabcabcabcbabcabcabcabaca
|
|
||||||
bcabcabcabcbabcabcabcabacabcabcabcacbcabcabcabcabacabcabcabcacbcabcabcabcbabcabcabcabaca
|
|
||||||
bcabcabcabcbabcabcabcabacabcabcabcacbcabcabcabcbabcabcabcabaca
|
|
||||||
bcabcabcabcbabcabcabcabacabcabcabcacbcabcabcabcbabcabcabcabacabcabcabcacbcabcabcabcbabcabcabcabaca
|
|
||||||
bcabcabcacbcabcabcabcbabcabcabcabaca
|
|
||||||
bcabcabcacbcabcabcabcbabcabcabcabacabcabcabcacbcabcabcabcbabcabcabcabacabcabcabaca
|
|
||||||
bcabcabcacbcabcabcabcbabcabcabcabacabcabcabaca
|
|
||||||
bcabcabcacbcabcabcabcbabcabcabcbabcabcabcabacabcabcabaca
|
|
||||||
bcabcabcacbcabcabcacbcabcabcabcbabcabcabcbabcabcabcabacabcabcabaca
|
|
||||||
bcabcabcacbcabcabcacbcabcabcabcbabcabcabcbabcabcabcabacabcabcabacabcabcabaca
|
|
||||||
bcabcabcacbcabcabcacbcabcabcabcbabcabcabcbabcabcabcbabcabcabcabacabcabcabacabcabcabaca
|
|
||||||
bcabcabcacbcabcabcacbcabcabcacbcabcabcabcbabcabcabcbabcabcabcbabcabcabcabacabcabcabacabcabcabaca
|
|
||||||
bcabcabaca
|
|
||||||
bcabcabacabcabcabacabcabcabacabcabcbabcabcabcbabcabcabcbabcabcacbcabcabcacbcabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcabacabcabcbabcabcabcbabcabcabcbabcabcacbcabcabcacbcabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcabacabcabcbabcabcabcbabcabcabcbabcabcacbcabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcabacabcabcbabcabcabcbabcabcacbcabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcbabcabcabcbabcabcacbcabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcbabcabcabcbabcabcacbcabcabcacbcabcabacabcabcabacabcabcbabcabcabcbabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcbabcabcabcbabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcbabcabcacbcabcabcacbcabcabacabcabcbabcabcabcbabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcbabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcbabcabcacbcabcabacabcabcbabcabcabcbabcabcacbcabcabacabcabcbabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcbabcabcacbcabcabacabcabcbabcabcacbcabcabaca
|
|
||||||
bcabcabacabcabcbabcabcacbcabcabacabcabcbabcabcacbcabcabacabcabcbabcabcacbcabcabaca
|
|
||||||
bcabcbabcabcacbcabcabaca
|
|
||||||
bcabcbabcabcacbcabcabacabcabcbabcabcacbcabcabacabcabcbabcabcacbcabcabacabcabcbabcabaca
|
|
||||||
bcabcbabcabcacbcabcabacabcabcbabcabcacbcabcabacabcabcbabcabaca
|
|
||||||
bcabcbabcabcacbcabcabacabcabcbabcabcacbcabcabacabcacbcabcabacabcabcbabcabcacbcabcabacabcabcbabcabaca
|
|
||||||
bcabcbabcabcacbcabcabacabcabcbabcabaca
|
|
||||||
bcabcbabcabcacbcabcabacabcacbcabcabacabcabcbabcabcacbcabcbabcabcacbcabcabacabcabcbabcabaca
|
|
||||||
bcabcbabcabcacbcabcabacabcacbcabcabacabcabcbabcabaca
|
|
||||||
bcabcbabcabcacbcabcbabcabcacbcabcabacabcacbcabcabacabcabcbabcabaca
|
|
||||||
bcabcbabcabcacbcabcbabcabcacbcabcabacabcacbcabcabacabcabcbabcabacabcabcbabcabaca
|
|
||||||
bcabcbabcabcacbcabcbabcabcacbcabcabacabcacbcabcabacabcacbcabcabacabcabcbabcabacabcabcbabcabaca
|
|
||||||
bcabcbabcabaca
|
|
||||||
bcabcbabcabacabcabcbabcabacabcacbcabcabacabcacbcabcabacabcacbcabcbabcabcacbcabcbabcabaca
|
|
||||||
bcabcbabcabacabcabcbabcabacabcacbcabcabacabcacbcabcbabcabcacbcabcbabcabaca
|
|
||||||
bcabcbabcabacabcacbcabcabacabcacbcabcbabcabcacbcabcbabcabaca
|
|
||||||
bcabcbabcabacabcacbcabcabacabcacbcabcbabcabaca
|
|
||||||
bcabcbabcabacabcacbcabcbabcabcacbcabcbabcabacabcacbcabcabacabcacbcabcbabcabaca
|
|
||||||
bcabcbabcabacabcacbcabcbabcabaca
|
|
||||||
bcabcbabcabacabcacbcabcbabcabacabcacbcabcabacabcacbcabcbabcabacabcacbcabcbabcabaca
|
|
||||||
bcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabaca
|
|
||||||
bcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabaca
|
|
||||||
bcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabaca
|
|
||||||
bcacbcabcbabcabaca
|
|
||||||
bcacbcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcabacabcacbcabcbabcabacabcacbcabcbabcbabcabacabcacbcabcbabcabacabcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcabacabcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcabacabcacbcabcbabcbabcabacabcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcabacabcacbcacbcabcbabcabacabcacbcabcbabcbabcabacabcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcabacabacabcacbcabcbabcbabcabacabcacbcabcbabcbabcabacabcacbcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcabacabacabcacbcabcbabcbabcabacabcacbcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcbabcabacabcacbcacbcabcbabcabacabaca
|
|
||||||
bcacbcabcbabcbabcabacabcacbcacbcabcbabcabacabacabcacbcabcbabcbabcabacabaca
|
|
||||||
bcacbcabcbabcbabcabacabcacbcacbcabcbabcabacabacabcacbcacbcabcbabcabacabacabcacbcabcbabcbabcabacabaca
|
|
||||||
bcacbcabcbabcbabcabacabaca
|
|
||||||
bcacbcabcbabcbabcabacabacabcacbcacbcabcbabcabacabacabcacbcacbcabcbabcbabcabacabaca
|
|
||||||
bcacbcabcbabcbabcabacabacabcacbcacbcabcbabcbabcabacabaca
|
|
||||||
bcacbcabcbabcbabcabacabacabcacbcacbcabcbabcbabcabacabacabcacbcacbcabcbabcbabcabacabaca
|
|
||||||
bcacbcacbcabcbabcbabcabacabaca
|
|
||||||
bcacbcacbcabcbabcbabcabacabacabcacbcacbcabcbabcbabcabacabacabcacbcacbcabcbabcbabcabacabacabaca
|
|
||||||
bcacbcacbcabcbabcbabcabacabacabcacbcacbcabcbabcbabcabacabacabaca
|
|
||||||
bcacbcacbcabcbabcbabcabacabacabcacbcacbcabcbabcbabcbabcabacabacabcacbcacbcabcbabcbabcabacabacabaca
|
|
||||||
bcacbcacbcabcbabcbabcabacabacabaca
|
|
||||||
bcacbcacbcabcbabcbabcbabcabacabacabcacbcacbcacbcabcbabcbabcabacabacabaca
|
|
||||||
bcacbcacbcabcbabcbabcbabcabacabacabaca
|
|
||||||
bcacbcacbcabcbabcbabcbabcabacabacabacabcacbcacbcacbcabcbabcbabcbabcabacabacabaca
|
|
||||||
bcacbcacbcacbcabcbabcbabcbabcabacabacabaca
|
|
||||||
bcacbcacbcacbcabcbabcbabcbabcabacabacabacabcacbcacbcacbcabcbabcbabcbabcabacabacabacabaca
|
|
||||||
bcacbcacbcacbcabcbabcbabcbabcabacabacabacabaca
|
|
||||||
bcacbcacbcacbcabcbabcbabcbabcbabcabacabacabacabcacbcacbcacbcacbcabcbabcbabcbabcabacabacabacabaca
|
|
||||||
bcacbcacbcacbcabcbabcbabcbabcbabcabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcabcbabcbabcbabcbabcabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcabcbabcbabcbabcbabcabacabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcabcbabcbabcbabcbabcbabcabacabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcacbcabcbabcbabcbabcbabcbabcabacabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcacbcabcbabcbabcbabcbabcbabcabacabacabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcacbcabcbabcbabcbabcbabcbabcbabcabacabacabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcacbcacbcabcbabcbabcbabcbabcbabcbabcabacabacabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcacbcacbcabcbabcbabcbabcbabcbabcbabcabacabacabacabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcacbcacbcabcbabcbabcbabcbabcbabcbabcbabcabacabacabacabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcacbcacbcacbcabcbabcbabcbabcbabcbabcbabcbabcabacabacabacabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcacbcacbcacbcabcbabcbabcbabcbabcbabcbabcbabcabacabacabacabacabacabacabacabaca
|
|
||||||
bcacbcacbcacbcacbcacbcacbcacbcabcbabcbabcbabcbabcbabcbabcbabcbabcabacabacabacabacabacabacabacabaca
|
|
||||||
baca
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 131 KiB |
Loading…
Reference in New Issue
Block a user