continue limit curve past degeneration point
This commit is contained in:
parent
000d8a53b9
commit
e631dee661
105
limit_set.c
105
limit_set.c
@ -52,6 +52,8 @@ int show_boxes = 0;
|
|||||||
int show_attractors = 0;
|
int show_attractors = 0;
|
||||||
int show_reflectors = 0;
|
int show_reflectors = 0;
|
||||||
int show_limit = 1;
|
int show_limit = 1;
|
||||||
|
int limit_with_lines = 1;
|
||||||
|
int use_repelling = 1;
|
||||||
|
|
||||||
void cartanMatrix(gsl_matrix *cartan, double a1, double a2, double a3, double s)
|
void cartanMatrix(gsl_matrix *cartan, double a1, double a2, double a3, double s)
|
||||||
{
|
{
|
||||||
@ -157,7 +159,7 @@ void drawPolygon(DrawingContext *ctx, int sides, point_t a, point_t b, point_t c
|
|||||||
drawSegment(ctx, d, a);
|
drawSegment(ctx, d, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixedPoints(const char *word, point_t *out)
|
int fixedPoints(const char *word, point_t *out)
|
||||||
{
|
{
|
||||||
gsl_matrix *tmp = ws->stack[10];
|
gsl_matrix *tmp = ws->stack[10];
|
||||||
gsl_matrix *ev = ws->stack[11];
|
gsl_matrix *ev = ws->stack[11];
|
||||||
@ -168,11 +170,13 @@ void fixedPoints(const char *word, point_t *out)
|
|||||||
continue;
|
continue;
|
||||||
multiply_right(tmp, gen[word[i]-'a'], ws);
|
multiply_right(tmp, gen[word[i]-'a'], ws);
|
||||||
}
|
}
|
||||||
eigenvectors(tmp, ev, ws);
|
int count = real_eigenvectors(tmp, ev, ws);
|
||||||
multiply_left(cob, ev, ws);
|
multiply_left(cob, ev, ws);
|
||||||
|
|
||||||
LOOP(i) out[i].x = gsl_matrix_get(ev, 0, i) / gsl_matrix_get(ev, 2, i);
|
LOOP(i) out[i].x = gsl_matrix_get(ev, 0, i) / gsl_matrix_get(ev, 2, i);
|
||||||
LOOP(i) out[i].y = gsl_matrix_get(ev, 1, i) / gsl_matrix_get(ev, 2, i);
|
LOOP(i) out[i].y = gsl_matrix_get(ev, 1, i) / gsl_matrix_get(ev, 2, i);
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawAttractorConnection(DrawingContext *ctx, const char *word1, const char *word2)
|
void drawAttractorConnection(DrawingContext *ctx, const char *word1, const char *word2)
|
||||||
@ -233,6 +237,8 @@ int computeLimitCurve()
|
|||||||
int p = 5, q = 5, r = 5;
|
int p = 5, q = 5, r = 5;
|
||||||
int k = 2, l = 2, m = 2;
|
int k = 2, l = 2, m = 2;
|
||||||
|
|
||||||
|
int column = use_repelling ? 2 : 0;
|
||||||
|
|
||||||
generate_triangle_group(group, n_group_elements, p, q, r);
|
generate_triangle_group(group, n_group_elements, p, q, r);
|
||||||
|
|
||||||
// do first in the Fuchsian case to get the angles
|
// do first in the Fuchsian case to get the angles
|
||||||
@ -243,14 +249,16 @@ int computeLimitCurve()
|
|||||||
multiply(matrices[group[i].parent->id], gen[group[i].letter], matrices[i]);
|
multiply(matrices[group[i].parent->id], gen[group[i].letter], matrices[i]);
|
||||||
diagonalize_symmetric_form(cartan, cob, ws);
|
diagonalize_symmetric_form(cartan, cob, ws);
|
||||||
multiply_many(ws, coxeter, 3, gen[0], gen[1], gen[2]);
|
multiply_many(ws, coxeter, 3, gen[0], gen[1], gen[2]);
|
||||||
if(!eigenvectors(coxeter, coxeter_fixedpoints, ws))
|
int ev_count_fuchsian = real_eigenvectors(coxeter, coxeter_fixedpoints, ws);
|
||||||
|
|
||||||
|
if(ev_count_fuchsian != 3)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for(int i = 0; i < n_group_elements; i++) {
|
for(int i = 0; i < n_group_elements; i++) {
|
||||||
multiply_many(ws, fixedpoints, 3, cob, matrices[i], coxeter_fixedpoints);
|
multiply_many(ws, fixedpoints, 3, cob, matrices[i], coxeter_fixedpoints);
|
||||||
limit_curve[3*i+2] = atan2(
|
limit_curve[3*i+2] = atan2(
|
||||||
gsl_matrix_get(fixedpoints, 0, 0)/gsl_matrix_get(fixedpoints, 2, 0),
|
gsl_matrix_get(fixedpoints, 0, column)/gsl_matrix_get(fixedpoints, 2, column),
|
||||||
gsl_matrix_get(fixedpoints, 1, 0)/gsl_matrix_get(fixedpoints, 2, 0));
|
gsl_matrix_get(fixedpoints, 1, column)/gsl_matrix_get(fixedpoints, 2, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now to it again to calculate x and y coordinates
|
// now to it again to calculate x and y coordinates
|
||||||
@ -262,14 +270,18 @@ int computeLimitCurve()
|
|||||||
gsl_matrix_memcpy(cob, cartan); // is this a good choice of basis
|
gsl_matrix_memcpy(cob, cartan); // is this a good choice of basis
|
||||||
// gsl_matrix_set_identity(cob);
|
// gsl_matrix_set_identity(cob);
|
||||||
multiply_many(ws, coxeter, 3, gen[0], gen[1], gen[2]);
|
multiply_many(ws, coxeter, 3, gen[0], gen[1], gen[2]);
|
||||||
if(!eigenvectors(coxeter, coxeter_fixedpoints, ws))
|
int ev_count = real_eigenvectors(coxeter, coxeter_fixedpoints, ws);
|
||||||
|
|
||||||
|
if(ev_count == 1)
|
||||||
|
column = 0;
|
||||||
|
if(ev_count == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for(int i = 0; i < n_group_elements; i++) {
|
for(int i = 0; i < n_group_elements; i++) {
|
||||||
multiply_many(ws, fixedpoints, 3, cob, matrices[i], coxeter_fixedpoints);
|
multiply_many(ws, fixedpoints, 3, cob, matrices[i], coxeter_fixedpoints);
|
||||||
|
|
||||||
limit_curve[3*i] = gsl_matrix_get(fixedpoints, 0, 0)/gsl_matrix_get(fixedpoints, 2, 0);
|
limit_curve[3*i] = gsl_matrix_get(fixedpoints, 0, column)/gsl_matrix_get(fixedpoints, 2, column);
|
||||||
limit_curve[3*i+1] = gsl_matrix_get(fixedpoints, 1, 0)/gsl_matrix_get(fixedpoints, 2, 0);
|
limit_curve[3*i+1] = gsl_matrix_get(fixedpoints, 1, column)/gsl_matrix_get(fixedpoints, 2, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(limit_curve, n_group_elements, 3*sizeof(double), compareAngle);
|
qsort(limit_curve, n_group_elements, 3*sizeof(double), compareAngle);
|
||||||
@ -281,14 +293,12 @@ void drawBoxes(DrawingContext *ctx)
|
|||||||
{
|
{
|
||||||
cairo_t *C = ctx->cairo;
|
cairo_t *C = ctx->cairo;
|
||||||
|
|
||||||
/*
|
|
||||||
cairo_set_source_rgb(C, 1, 0, 0);
|
cairo_set_source_rgb(C, 1, 0, 0);
|
||||||
drawBoxStd(ctx, "c", 'C');
|
drawBoxStd(ctx, "c", 'C');
|
||||||
drawBoxStd(ctx, "", 'B');
|
drawBoxStd(ctx, "", 'B');
|
||||||
drawBoxStd(ctx, "a", 'A');
|
drawBoxStd(ctx, "a", 'A');
|
||||||
drawBoxStd(ctx, "", 'C');
|
drawBoxStd(ctx, "", 'C');
|
||||||
drawBoxStd(ctx, "b", 'B');
|
drawBoxStd(ctx, "b", 'B');
|
||||||
*/
|
|
||||||
|
|
||||||
cairo_set_source_rgb(C, 0, 0, 0);
|
cairo_set_source_rgb(C, 0, 0, 0);
|
||||||
drawBoxStd(ctx, "ca", 'A');
|
drawBoxStd(ctx, "ca", 'A');
|
||||||
@ -297,9 +307,6 @@ void drawBoxes(DrawingContext *ctx)
|
|||||||
drawBoxStd(ctx, "acac", 'C');
|
drawBoxStd(ctx, "acac", 'C');
|
||||||
drawBoxStd(ctx, "aca", 'A');
|
drawBoxStd(ctx, "aca", 'A');
|
||||||
drawBoxStd(ctx, "ac", 'C');
|
drawBoxStd(ctx, "ac", 'C');
|
||||||
|
|
||||||
cairo_set_source_rgb(C, 1, 0, 1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
drawBoxStd(ctx, "aca cb", 'B');
|
drawBoxStd(ctx, "aca cb", 'B');
|
||||||
drawBoxStd(ctx, "aca cbc", 'C');
|
drawBoxStd(ctx, "aca cbc", 'C');
|
||||||
@ -307,14 +314,31 @@ void drawBoxes(DrawingContext *ctx)
|
|||||||
drawBoxStd(ctx, "aca bcbc", 'C');
|
drawBoxStd(ctx, "aca bcbc", 'C');
|
||||||
drawBoxStd(ctx, "aca bcb", 'B');
|
drawBoxStd(ctx, "aca bcb", 'B');
|
||||||
drawBoxStd(ctx, "aca bc", 'C');
|
drawBoxStd(ctx, "aca bc", 'C');
|
||||||
|
|
||||||
|
drawBoxStd(ctx, "caca cb", 'B');
|
||||||
|
drawBoxStd(ctx, "caca cbc", 'C');
|
||||||
|
drawBoxStd(ctx, "caca cbcb", 'B');
|
||||||
|
drawBoxStd(ctx, "caca bcbc", 'C');
|
||||||
|
drawBoxStd(ctx, "caca bcb", 'B');
|
||||||
|
drawBoxStd(ctx, "caca bc", 'C');
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
cairo_set_source_rgb(C, 1, 0, 1);
|
||||||
drawBoxStd(ctx, "ca bc", 'C');
|
drawBoxStd(ctx, "ca bc", 'C');
|
||||||
drawBoxStd(ctx, "ca bcb", 'B');
|
drawBoxStd(ctx, "ca bcb", 'B');
|
||||||
drawBoxStd(ctx, "ca bcbc", 'C');
|
drawBoxStd(ctx, "ca bcbc", 'C');
|
||||||
drawBoxStd(ctx, "ca cbcb", 'B');
|
drawBoxStd(ctx, "ca cbcb", 'B');
|
||||||
drawBoxStd(ctx, "ca cbc", 'C');
|
drawBoxStd(ctx, "ca cbc", 'C');
|
||||||
drawBoxStd(ctx, "ca cb", 'B');
|
drawBoxStd(ctx, "ca cb", 'B');
|
||||||
|
|
||||||
|
cairo_set_source_rgb(C, 0, 1, 0);
|
||||||
|
// drawBoxStd(ctx, "ca bc", 'C');
|
||||||
|
drawBoxStd(ctx, "cabc ba", 'A');
|
||||||
|
drawBoxStd(ctx, "cabc bab", 'B');
|
||||||
|
drawBoxStd(ctx, "cabc baba", 'A');
|
||||||
|
drawBoxStd(ctx, "cabc abab", 'B');
|
||||||
|
drawBoxStd(ctx, "cabc aba", 'A');
|
||||||
|
drawBoxStd(ctx, "cabc ab", 'B');
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawReflectors(DrawingContext *ctx)
|
void drawReflectors(DrawingContext *ctx)
|
||||||
@ -373,7 +397,9 @@ void draw(DrawingContext *ctx)
|
|||||||
|
|
||||||
if(limit_curve_valid) {
|
if(limit_curve_valid) {
|
||||||
if(show_limit) {
|
if(show_limit) {
|
||||||
int last_inside = 0;
|
cairo_save(C);
|
||||||
|
|
||||||
|
int previous_inside = 0;
|
||||||
for(int i = 0; i < n_group_elements; i++) {
|
for(int i = 0; i < n_group_elements; i++) {
|
||||||
double x = limit_curve[3*i];
|
double x = limit_curve[3*i];
|
||||||
double y = limit_curve[3*i+1];
|
double y = limit_curve[3*i+1];
|
||||||
@ -381,19 +407,30 @@ void draw(DrawingContext *ctx)
|
|||||||
cairo_user_to_device(C, &x, &y);
|
cairo_user_to_device(C, &x, &y);
|
||||||
|
|
||||||
if(-x < ctx->width && x < 3*ctx->width && -y < ctx->height && y < 3*ctx->height) {
|
if(-x < ctx->width && x < 3*ctx->width && -y < ctx->height && y < 3*ctx->height) {
|
||||||
if(!last_inside) {
|
if(limit_with_lines) {
|
||||||
|
if(!previous_inside)
|
||||||
cairo_move_to(C, limit_curve[3*i], limit_curve[3*i+1]);
|
cairo_move_to(C, limit_curve[3*i], limit_curve[3*i+1]);
|
||||||
} else {
|
else
|
||||||
cairo_line_to(C, limit_curve[3*i], limit_curve[3*i+1]);
|
cairo_line_to(C, limit_curve[3*i], limit_curve[3*i+1]);
|
||||||
}
|
|
||||||
last_inside = 1;
|
|
||||||
} else {
|
} else {
|
||||||
last_inside = 0;
|
cairo_move_to(C, limit_curve[3*i], limit_curve[3*i+1]);
|
||||||
|
cairo_close_path(C);
|
||||||
}
|
}
|
||||||
|
previous_inside = 1;
|
||||||
|
} else {
|
||||||
|
previous_inside = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!limit_with_lines) { // draw dots instead of lines
|
||||||
|
cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
|
||||||
|
cairo_set_line_width(C, 3.0/ctx->scalefactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_set_source_rgb(C, 0, 0, 0);
|
cairo_set_source_rgb(C, 0, 0, 0);
|
||||||
cairo_stroke(C);
|
cairo_stroke(C);
|
||||||
|
|
||||||
|
cairo_restore(C);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(show_boxes)
|
if(show_boxes)
|
||||||
@ -411,7 +448,7 @@ void draw(DrawingContext *ctx)
|
|||||||
cairo_move_to(C, 15, 30);
|
cairo_move_to(C, 15, 30);
|
||||||
cairo_set_source_rgb(C, 0, 0, 0);
|
cairo_set_source_rgb(C, 0, 0, 0);
|
||||||
char buf[100];
|
char buf[100];
|
||||||
sprintf(buf, "t = %.8f", parameter);
|
sprintf(buf, "t = exp(%.8f) = %.8f", log(parameter), parameter);
|
||||||
cairo_show_text(C, buf);
|
cairo_show_text(C, buf);
|
||||||
|
|
||||||
cairo_surface_flush(cairo_get_target(C));
|
cairo_surface_flush(cairo_get_target(C));
|
||||||
@ -419,7 +456,7 @@ void draw(DrawingContext *ctx)
|
|||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
n_group_elements = 100000;
|
n_group_elements = 50000;
|
||||||
limit_curve = malloc(3*n_group_elements*sizeof(double));
|
limit_curve = malloc(3*n_group_elements*sizeof(double));
|
||||||
group = malloc(n_group_elements*sizeof(groupelement_t));
|
group = malloc(n_group_elements*sizeof(groupelement_t));
|
||||||
ws = workspace_alloc(3);
|
ws = workspace_alloc(3);
|
||||||
@ -490,14 +527,30 @@ int processEvent(GraphicsInfo *info, XEvent *ev)
|
|||||||
printf("Key pressed: %ld\n", key);
|
printf("Key pressed: %ld\n", key);
|
||||||
|
|
||||||
switch(key) {
|
switch(key) {
|
||||||
case '<':
|
case XK_Down:
|
||||||
parameter /= exp(0.002);
|
parameter /= exp(0.002);
|
||||||
limit_curve_valid = computeLimitCurve();
|
limit_curve_valid = computeLimitCurve();
|
||||||
break;
|
break;
|
||||||
case '>':
|
case XK_Up:
|
||||||
parameter *= exp(0.002);
|
parameter *= exp(0.002);
|
||||||
limit_curve_valid = computeLimitCurve();
|
limit_curve_valid = computeLimitCurve();
|
||||||
break;
|
break;
|
||||||
|
case XK_Left:
|
||||||
|
parameter /= exp(0.0001);
|
||||||
|
limit_curve_valid = computeLimitCurve();
|
||||||
|
break;
|
||||||
|
case XK_Right:
|
||||||
|
parameter *= exp(0.0001);
|
||||||
|
limit_curve_valid = computeLimitCurve();
|
||||||
|
break;
|
||||||
|
case XK_Page_Down:
|
||||||
|
parameter /= exp(0.2);
|
||||||
|
limit_curve_valid = computeLimitCurve();
|
||||||
|
break;
|
||||||
|
case XK_Page_Up:
|
||||||
|
parameter *= exp(0.2);
|
||||||
|
limit_curve_valid = computeLimitCurve();
|
||||||
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
parameter = 2.890053638;
|
parameter = 2.890053638;
|
||||||
limit_curve_valid = computeLimitCurve();
|
limit_curve_valid = computeLimitCurve();
|
||||||
@ -523,12 +576,18 @@ int processEvent(GraphicsInfo *info, XEvent *ev)
|
|||||||
case 'r':
|
case 'r':
|
||||||
show_reflectors = !show_reflectors;
|
show_reflectors = !show_reflectors;
|
||||||
break;
|
break;
|
||||||
|
case 'L':
|
||||||
|
limit_with_lines = !limit_with_lines;
|
||||||
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
show_limit = !show_limit;
|
show_limit = !show_limit;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
print(info->context);
|
print(info->context);
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
use_repelling = !use_repelling;
|
||||||
|
limit_curve_valid = computeLimitCurve();
|
||||||
}
|
}
|
||||||
|
|
||||||
return STATUS_REDRAW;
|
return STATUS_REDRAW;
|
||||||
|
23
linalg.c
23
linalg.c
@ -190,6 +190,29 @@ int eigenvectors(gsl_matrix *g, gsl_matrix *evec_real, workspace_t *ws)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only fills in the real eigenvectors and returns their count
|
||||||
|
int real_eigenvectors(gsl_matrix *g, gsl_matrix *evec_real, workspace_t *ws)
|
||||||
|
{
|
||||||
|
gsl_matrix_memcpy(ws->stack[0], g);
|
||||||
|
gsl_eigen_nonsymmv_params(0, ws->work_nonsymmv);
|
||||||
|
int r = gsl_eigen_nonsymmv(ws->stack[0], ws->eval_complex, ws->evec_complex, ws->work_nonsymmv);
|
||||||
|
ERROR(r, "gsl_eigen_nonsymmv failed!\n");
|
||||||
|
|
||||||
|
gsl_eigen_nonsymmv_sort(ws->eval_complex, ws->evec_complex, GSL_EIGEN_SORT_ABS_DESC);
|
||||||
|
|
||||||
|
int real = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < ws->n; i++) {
|
||||||
|
if(FCMP(GSL_IMAG(gsl_vector_complex_get(ws->eval_complex, i)), 0) == 0) {// real
|
||||||
|
for(int j = 0; j < ws->n; j++)
|
||||||
|
gsl_matrix_set(evec_real, j, real, GSL_REAL(gsl_matrix_complex_get(ws->evec_complex, j, i)));
|
||||||
|
real++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return real;
|
||||||
|
}
|
||||||
|
|
||||||
void eigensystem_symm(gsl_matrix *g, gsl_vector *eval, gsl_matrix *evec, workspace_t *ws)
|
void eigensystem_symm(gsl_matrix *g, gsl_vector *eval, gsl_matrix *evec, workspace_t *ws)
|
||||||
{
|
{
|
||||||
gsl_matrix_memcpy(ws->stack[0], g);
|
gsl_matrix_memcpy(ws->stack[0], g);
|
||||||
|
1
linalg.h
1
linalg.h
@ -42,6 +42,7 @@ int jordan_calc(gsl_matrix *g, double *mu, workspace_t *ws);
|
|||||||
double trace(gsl_matrix *g);
|
double trace(gsl_matrix *g);
|
||||||
double determinant(gsl_matrix *g, workspace_t *ws);
|
double determinant(gsl_matrix *g, workspace_t *ws);
|
||||||
int eigenvectors(gsl_matrix *g, gsl_matrix *evec, workspace_t *ws);
|
int eigenvectors(gsl_matrix *g, gsl_matrix *evec, workspace_t *ws);
|
||||||
|
int real_eigenvectors(gsl_matrix *g, gsl_matrix *evec, workspace_t *ws);
|
||||||
void eigenvectors_symm(gsl_matrix *g, gsl_vector *eval, gsl_matrix *evec, workspace_t *ws);
|
void eigenvectors_symm(gsl_matrix *g, gsl_vector *eval, gsl_matrix *evec, workspace_t *ws);
|
||||||
int diagonalize_symmetric_form(gsl_matrix *A, gsl_matrix *cob, workspace_t *ws);
|
int diagonalize_symmetric_form(gsl_matrix *A, gsl_matrix *cob, workspace_t *ws);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user