Compare commits

..

6 Commits

Author SHA1 Message Date
Florian Stecker
1b1880fe19 add documentation 2023-01-17 11:20:25 -05:00
Florian Stecker
c62044d637 allow rotations 2023-01-08 10:22:53 -05:00
Florian Stecker
040f994d6f add convenience script 2022-06-12 13:22:40 +02:00
Florian Stecker
920f4b568b simplify Makefile and add new .gitignore 2022-06-12 12:45:24 +02:00
Florian Stecker
9af377e0a9 delete some old pictures and some random other changes 2022-06-12 11:54:22 +02:00
Florian Stecker
2f14076337 redo hyperbolic pictures 2022-03-02 10:48:04 -06:00
11 changed files with 184 additions and 180 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
*.o
hyperbolic
output/
README.html

View File

@@ -7,61 +7,19 @@ SPECIAL_OPTIONS=-O3 -flto -funroll-loops -Winline
OPTIONS=-m64 -march=native -mtune=native -std=gnu99 -D_GNU_SOURCE $(SPECIAL_OPTIONS) OPTIONS=-m64 -march=native -mtune=native -std=gnu99 -D_GNU_SOURCE $(SPECIAL_OPTIONS)
all: discreteness singular_values nondiscrete traces element_path limit_set hyperbolic ellipticity all: hyperbolic
singular_values: singular_values.o triangle.o linalg.o
gcc $(OPTIONS) -o singular_values triangle.o linalg.o singular_values.o -lm -lgsl -lcblas
nondiscrete: nondiscrete.o triangle.o linalg.o
gcc $(OPTIONS) -o nondiscrete triangle.o linalg.o nondiscrete.o -lm -lgsl -lcblas
traces: traces.o triangle.o linalg.o
gcc $(OPTIONS) -o traces triangle.o linalg.o traces.o -lm -lgsl -lcblas
discreteness: discreteness.o triangle.o linalg.o
gcc $(OPTIONS) -o discreteness triangle.o linalg.o discreteness.o -lm -lgsl -lcblas
element_path: element_path.o linalg.o
gcc $(OPTIONS) -o element_path element_path.o linalg.o -lm -lgsl -lcblas
limit_set: limit_set.o linalg.o triangle.o
gcc $(OPTIONS) -o limit_set limit_set.o linalg.o triangle.o -lm -lgsl -lcblas
hyperbolic: hyperbolic.o triangle.o linalg.o hyperbolic: hyperbolic.o triangle.o linalg.o
gcc $(OPTIONS) -o hyperbolic hyperbolic.o triangle.o linalg.o -lm -lgsl -lcblas gcc $(OPTIONS) -o hyperbolic hyperbolic.o triangle.o linalg.o -lm -lgsl -lcblas
ellipticity: ellipticity.o triangle.o linalg.o
gcc $(OPTIONS) -o ellipticity ellipticity.o triangle.o linalg.o -lm -lgsl -lcblas
singular_values.o: singular_values.c $(HEADERS)
gcc $(OPTIONS) -c singular_values.c
nondiscrete.o: nondiscrete.c $(HEADERS)
gcc $(OPTIONS) -c nondiscrete.c
traces.o: traces.c $(HEADERS)
gcc $(OPTIONS) -c traces.c
discreteness.o: discreteness.c $(HEADERS)
gcc $(OPTIONS) -c discreteness.c
element_path.o: element_path.c $(HEADERS)
gcc $(OPTIONS) -c element_path.c
linalg.o: linalg.c $(HEADERS) linalg.o: linalg.c $(HEADERS)
gcc $(OPTIONS) -c linalg.c gcc $(OPTIONS) -c linalg.c
triangle.o: triangle.c $(HEADERS) triangle.o: triangle.c $(HEADERS)
gcc $(OPTIONS) -c triangle.c gcc $(OPTIONS) -c triangle.c
limit_set.o: limit_set.c $(HEADERS)
gcc $(OPTIONS) -c limit_set.c
hyperbolic.o: hyperbolic.c $(HEADERS) hyperbolic.o: hyperbolic.c $(HEADERS)
gcc $(OPTIONS) -c hyperbolic.c gcc $(OPTIONS) -c hyperbolic.c
ellipticity.o: ellipticity.c $(HEADERS)
gcc $(OPTIONS) -c ellipticity.c
clean: clean:
rm -f singular_values nondiscrete traces discreteness element_path limit_set hyperbolic ellipticity triangle.o linalg.o singular_values.o nondiscrete.o traces.o discreteness.o element_path.o limit_set.o hyperbolic.o ellipticity.o rm -f hyperbolic triangle.o linalg.o hyperbolic.o

49
README.md Normal file
View File

@@ -0,0 +1,49 @@
# hyperbolic tilings #
A program to draw regular tilings of the hyperbolic plane by triangles as SVG files.
## Setup ##
GCC and GNU make are needed. To compile, just run `make`.
## Usage ##
The executable is called `hyperbolic` and is invoked as follows:
$ ./hyperbolic
Usage: ./hyperbolic <p> <q> <r> <n_elements> <word1> <word2> ...
The arguments `p,q,r` specify the orders of the rotations `bc`, `ca` and `ab`, where `a,b,c` are the reflections along the three sides of the triangle. The parameter `n_elements` limits how many translates of the triangle are being drawn (1000 is a good default value, although for some values of `p,q,r` more are needed).
The program can not only draw the tiling by triangles, but also the axes of specific hyperbolic elements in the triangle group or the fixed points of elliptic elements. To use this feature, just specify the group elements as additional arguments, written as words in the three reflections `a,b,c`. This will draw its axis/fixed point and that of all of its conjugates.
## Examples ##
./hyperbolic 5 5 5 5000 abc
![(5,5,5) tiling with axes of abc and its conjugates](https://florianstecker.net/git_files/hyperbolic_tilings/tiling_555_abc.png)
./hyperbolic 2 3 7 20000
![(2,3,7) tiling](https://florianstecker.net/git_files/hyperbolic_tilings/tiling_237.png)
./hyperbolic 2 3 7 20000 ab
![(2,3,7) tiling](https://florianstecker.net/git_files/hyperbolic_tilings/tiling_237_ab.png)
## Conversion to PDF or PNG ##
If a different image format is required, the SVG files can easily be converted. Using [rsvg-convert] gives good results.
To convert to PNG (used for the images above):
rsvg-convert --format=png -w 600 -h 600 tiling_555_abc.svg -o tiling_555_abc.png
To convert to PDF:
rsvg-convert --format=pdf -w tiling_555_abc.svg -o tiling_555_abc.pdf
`maketiling.sh` is a convenience script which takes the same arguments as `hyperbolic`, but saves the SVG file in the folder `output/` (which has to be present) with a descriptive name and also converts it to PDF.
[rsvg-convert]: https://gitlab.gnome.org/GNOME/librsvg

View File

@@ -198,6 +198,16 @@ void draw_triangle(point *p, gsl_matrix *frame, const char *arguments)
#endif #endif
} }
void draw_dot(point p, gsl_matrix *frame, const char *arguments)
{
double x = coord(p, 0, frame);
double y = coord(p, 1, frame);
#ifdef POINCARE
printf("<circle cx=\"%f\" cy=\"%f\" r=\"6\" style=\"%s\"/>\n", CONV(x), CONV(y), arguments);
#endif
}
void draw_line(point p1, point p2, gsl_matrix *frame, const char *arguments) void draw_line(point p1, point p2, gsl_matrix *frame, const char *arguments)
{ {
char buffer[100]; char buffer[100];
@@ -217,11 +227,16 @@ void draw_line(point p1, point p2, gsl_matrix *frame, const char *arguments)
#endif #endif
} }
void compute_word(workspace_t *ws, gsl_matrix *result, gsl_matrix **gen, const char *word, int modifier) void compute_word(workspace_t *ws, gsl_matrix *result, gsl_matrix **gen, const char *word, int modifier, int inverse)
{ {
gsl_matrix_set_identity(result); gsl_matrix_set_identity(result);
if(inverse) {
for(int i = 0; word[i] != 0; i++)
multiply_left(gen[(word[i]-'a'+modifier)%3], result, ws);
} else {
for(int i = 0; word[i] != 0; i++) for(int i = 0; word[i] != 0; i++)
multiply_right(result, gen[(word[i]-'a'+modifier)%3], ws); multiply_right(result, gen[(word[i]-'a'+modifier)%3], ws);
}
} }
int main(int argc, const char *argv[]) int main(int argc, const char *argv[])
@@ -230,20 +245,22 @@ int main(int argc, const char *argv[])
gsl_matrix **matrices; gsl_matrix **matrices;
gsl_matrix *cartan; gsl_matrix *cartan;
gsl_matrix *gen[3]; gsl_matrix *gen[3];
gsl_matrix *coxeter[3]; gsl_matrix **special;
gsl_matrix *coxeter2[3]; gsl_matrix **special_eigenvectors;
gsl_matrix *coxeter_eigenvectors[3]; point *special_attracting, *special_repelling, *special_rotation;
gsl_matrix *coxeter_eigenvectors2[3];
gsl_matrix *frame; gsl_matrix *frame;
workspace_t *ws; workspace_t *ws;
int p,q,r;
int elements, nspecial, nspecial_hyp, nspecial_rot;
if(argc < 5) { if(argc < 5) {
fprintf(stderr, "Usage: %s <p> <q> <r> <n_elements>\n", argv[0]); fprintf(stderr, "Usage: %s <p> <q> <r> <n_elements> <word1> <word2> ...\n", argv[0]);
exit(1); exit(1);
} }
int elements = atoi(argv[4]); nspecial = argc - 5;
int p = atoi(argv[1]), q = atoi(argv[2]), r = atoi(argv[3]); elements = atoi(argv[4]);
p = atoi(argv[1]), q = atoi(argv[2]), r = atoi(argv[3]);
group = malloc(elements*sizeof(groupelement_t)); group = malloc(elements*sizeof(groupelement_t));
matrices = malloc(elements*sizeof(gsl_matrix*)); matrices = malloc(elements*sizeof(gsl_matrix*));
@@ -252,79 +269,56 @@ int main(int argc, const char *argv[])
cartan = gsl_matrix_alloc(3, 3); cartan = gsl_matrix_alloc(3, 3);
frame = gsl_matrix_alloc(3, 3); frame = gsl_matrix_alloc(3, 3);
LOOP(i) gen[i] = gsl_matrix_alloc(3, 3); LOOP(i) gen[i] = gsl_matrix_alloc(3, 3);
LOOP(i) coxeter[i] = gsl_matrix_alloc(3, 3);
LOOP(i) coxeter_eigenvectors[i] = gsl_matrix_alloc(3, 3);
LOOP(i) coxeter2[i] = gsl_matrix_alloc(3, 3);
LOOP(i) coxeter_eigenvectors2[i] = gsl_matrix_alloc(3, 3);
ws = workspace_alloc(3); ws = workspace_alloc(3);
special = malloc(3*nspecial*sizeof(gsl_matrix*));
special_eigenvectors = malloc(3*nspecial*sizeof(gsl_matrix*));
special_attracting = malloc(3*nspecial*sizeof(point));
special_repelling = malloc(3*nspecial*sizeof(point));
special_rotation = malloc(3*nspecial*sizeof(point));
for(int i = 0; i < 3*nspecial; i++) {
special[i] = gsl_matrix_alloc(3, 3);
special_eigenvectors[i] = gsl_matrix_alloc(3, 3);
}
generate_triangle_group(group, elements, p, q, r); generate_triangle_group(group, elements, p, q, r);
cartan_matrix(cartan, M_PI/p, M_PI/q, M_PI/r, 1.0); cartan_matrix(cartan, M_PI/p, M_PI/q, M_PI/r, 1.0);
initialize_triangle_generators(gen, cartan); initialize_triangle_generators(gen, cartan);
int pos = diagonalize_symmetric_form(cartan, frame, ws); // choose frame of reference which diagonalizes the form diagonalize_symmetric_form(cartan, frame, ws); // choose frame of reference which diagonalizes the form
gsl_matrix_set_identity(matrices[0]); gsl_matrix_set_identity(matrices[0]);
for(int i = 1; i < elements; i++) for(int i = 1; i < elements; i++)
multiply(matrices[group[i].parent->id], gen[group[i].letter], matrices[i]); multiply(matrices[group[i].parent->id], gen[group[i].letter], matrices[i]);
// LOOP(i) multiply_many(ws, coxeter[i], 3, gen[i%3], gen[(i+1)%3], gen[(i+2)%3]); // coxeter nspecial_hyp = nspecial_rot = 0;
// LOOP(i) multiply_many(ws, coxeter[i], 4, gen[i%3], gen[(i+1)%3], gen[i%3], gen[(i+2)%3]); // abcb for(int i = 0; i < nspecial; i++) {
LOOP(i) compute_word(ws, coxeter[i], gen, "abcb", i); int j = 0;
/* LOOP(i) multiply_many(ws, coxeter[i], 10, int nreal;
gen[i%3], gen[(i+1)%3], gen[(i+2)%3],
gen[i%3], gen[(i+1)%3], gen[(i+2)%3],
gen[i%3], gen[(i+1)%3], gen[(i+2)%3],
gen[(i+1)%3]); // (abc)^3 b */
LOOP(i) eigenvectors(coxeter[i], coxeter_eigenvectors[i], ws);
LOOP(i) eigenvectors(coxeter2[i], coxeter_eigenvectors2[i], ws);
/* compute_word(ws, special[3*i+j], gen, argv[i+5], j, 0);
for(int i = 0; i < elements; i++) { nreal = eigenvectors(special[3*i+j], special_eigenvectors[3*i+j], ws);
printf("%4d: ", i); if(nreal == 3) {
for(groupelement_t *cur = &group[i]; cur->parent; cur = cur->parent) special_attracting[nspecial_hyp] = column(special_eigenvectors[3*i+j], 0);
fputc(cur->letter+'a', stdout);
fputc('\n', stdout); // repelling = attracting of inverse
compute_word(ws, special[3*i+j], gen, argv[i+5], j, 1);
eigenvectors(special[3*i+j], special_eigenvectors[3*i+j], ws);
special_repelling[nspecial_hyp] = column(special_eigenvectors[3*i+j], 0);
nspecial_hyp++;
} else {
special_rotation[nspecial_rot] = column(special_eigenvectors[3*i+j], 0);
nspecial_rot++;
}
} }
return 0;*/ fprintf(stderr, "%d special elements, %d rotations, %d hyperbolic\n", nspecial, nspecial_rot, nspecial_hyp);
point coxeter_attracting[3];
point coxeter_repelling[3];
point coxeter_axes[3];
point coxeter2_attracting[3];
point coxeter2_repelling[3];
point coxeter2_axes[3];
point edge_midpoints[3];
point reflection_lines[3];
point triangle_points[3];
point transformed[3];
point transformed2[3];
point transformed3[3];
point transformed4[3];
point transformed5[3];
point transformed6[3];
point center;
LOOP(i) coxeter_attracting[i] = column(coxeter_eigenvectors[i], 0);
LOOP(i) coxeter_repelling[i] = column(coxeter_eigenvectors[i], 2);
LOOP(i) coxeter_axes[i] = incidence(coxeter_attracting[i], coxeter_repelling[i]);
LOOP(i) edge_midpoints[i] = incidence(coxeter_axes[(i+1)%3], coxeter_axes[(i+2)%3]);
LOOP(i) reflection_lines[i] = row(cartan, i);
LOOP(i) triangle_points[i] = incidence(reflection_lines[(i+1)%3], reflection_lines[(i+2)%3]);
LOOP(i) coxeter2_attracting[i] = column(coxeter_eigenvectors2[i], 0);
LOOP(i) coxeter2_repelling[i] = column(coxeter_eigenvectors2[i], 2);
LOOP(i) coxeter2_axes[i] = incidence(coxeter2_attracting[i], coxeter2_repelling[i]);
print_svg_header();
/*
// let's correct the frame of reference by using hyperbolic transformations // let's correct the frame of reference by using hyperbolic transformations
center = apply(frame, triangle_points[2]); center = apply(frame, triangle_points[2]);
double angle = atan2(center.x[1], center.x[0]); double angle = atan2(center.x[1], center.x[0]);
double boost = atanh(-sqrt(center.x[0]*center.x[0]+center.x[1]*center.x[1])/center.x[2]); double boost = atanh(-sqrt(center.x[0]*center.x[0]+center.x[1]*center.x[1])/center.x[2]);
gsl_matrix *frame_correction = gsl_matrix_alloc(3, 3); gsl_matrix *frame_correction = gsl_matrix_alloc(3, 3);
gsl_matrix_set_identity(frame_correction); gsl_matrix_set_identity(frame_correction);
/*
gsl_matrix_set(frame_correction, 0, 0, cos(angle-M_PI/2)); gsl_matrix_set(frame_correction, 0, 0, cos(angle-M_PI/2));
gsl_matrix_set(frame_correction, 0, 1, sin(angle-M_PI/2)); gsl_matrix_set(frame_correction, 0, 1, sin(angle-M_PI/2));
gsl_matrix_set(frame_correction, 1, 0, -sin(angle-M_PI/2)); gsl_matrix_set(frame_correction, 1, 0, -sin(angle-M_PI/2));
@@ -338,80 +332,69 @@ int main(int argc, const char *argv[])
gsl_matrix_set(frame_correction, 2, 0, sinh(-boost)); gsl_matrix_set(frame_correction, 2, 0, sinh(-boost));
gsl_matrix_set(frame_correction, 2, 2, cosh(-boost)); gsl_matrix_set(frame_correction, 2, 2, cosh(-boost));
multiply_left(frame_correction, frame, ws); multiply_left(frame_correction, frame, ws);
*/
gsl_matrix_free(frame_correction); gsl_matrix_free(frame_correction);
*/
// int indices[10] = {0, 1, 6, 10, 30, 46, 124, 185, 484, 717}; // the actual drawing
// int indices[10] = {0, 1, 4, 10, 22}; point transformed[3];
point reflection_lines[3];
point triangle_points[3];
print_svg_header();
for(int k = 0; k < elements; k++) { for(int k = 0; k < elements; k++) {
if(group[k].length % 2) if(group[k].length % 2)
continue; continue;
LOOP(i) reflection_lines[i] = row(cartan, i);
LOOP(i) triangle_points[i] = incidence(reflection_lines[(i+1)%3], reflection_lines[(i+2)%3]);
LOOP(i) transformed[i] = apply(matrices[k], triangle_points[i]); LOOP(i) transformed[i] = apply(matrices[k], triangle_points[i]);
// draw_triangle(transformed, frame, "black,fill=black!10,line width=0pt");
draw_triangle(transformed, frame, "fill:#cfcfcf;"); draw_triangle(transformed, frame, "fill:#cfcfcf;");
// draw_triangle(transformed, frame, "fill:#000000;");
} }
char stylestring[100];
char colors[3][20] = {"red", "blue", "green"};
// draw special elements
for(int k = 0; k < elements; k++) { for(int k = 0; k < elements; k++) {
// if(group[k].length % 2) // if(group[k].length % 2)
// continue; // continue;
LOOP(i) transformed[i] = apply(matrices[k], edge_midpoints[(i+2)%3]); for(int i = 0; i < nspecial_hyp; i+=3) {
LOOP(i) transformed2[i] = apply(matrices[k], coxeter_repelling[i]); // draw_dot(apply(matrices[k], special_repelling[i]), frame, "fill:red;stroke-width:1;");
LOOP(i) transformed3[i] = apply(matrices[k], coxeter_repelling[(i+1)%3]); // draw_dot(apply(matrices[k], special_attracting[i]), frame, "fill:blue;stroke-width:1;");
LOOP(i) transformed4[i] = apply(matrices[k], coxeter_attracting[i%3]); snprintf(stylestring, sizeof(stylestring), "fill:none;stroke:%s;stroke-width:1;", colors[i%3]);
LOOP(i) transformed5[i] = apply(matrices[k], coxeter2_repelling[i]); draw_line(apply(matrices[k], special_repelling[i]),
LOOP(i) transformed6[i] = apply(matrices[k], coxeter2_attracting[i%3]); apply(matrices[k], special_attracting[i]),
//LOOP(i) draw_line(transformed2[i], transformed4[i], frame, "red"); frame, stylestring);
draw_line(transformed2[0], transformed4[0], frame, "fill:none;stroke:red;stroke-width:1;"); }
// draw_line(transformed2[1], transformed4[1], frame, "fill:none;stroke:blue;stroke-width:1;");
// draw_line(transformed2[2], transformed4[2], frame, "fill:none;stroke:darkgreen;stroke-width:1;"); for(int i = 0; i < nspecial_rot; i+=3) {
snprintf(stylestring, sizeof(stylestring), "fill:%s;stroke:%s;stroke-width:1;", colors[i%3], colors[i%3]);
// draw_line(transformed5[0], transformed6[0], frame, "fill:none;stroke:blue;stroke-width:1;"); // fprintf(stderr, "%f %f\n", special_rotation[i].x[0], special_rotation[i].x[1]);
// draw_line(transformed5[1], transformed6[1], frame, "fill:none;stroke:blue;stroke-width:1;"); draw_dot(apply(matrices[k], special_rotation[i]), frame, stylestring);
// draw_line(transformed5[2], transformed6[2], frame, "fill:none;stroke:blue;stroke-width:1;"); }
// draw_line(transformed2[1], transformed4[1], frame, "fill:none;stroke:darkgreen;stroke-width:1;");
// draw_line(transformed2[2], transformed4[2], frame, "fill:none;stroke:blue;stroke-width:1;");
// LOOP(i) draw_line(transformed[i], transformed3[i], frame, "red");
// LOOP(i) transformed[i] = apply(matrices[k], coxeter_attracting[i]);
// draw_line(transformed[1], transformed[2], frame, "red");
} }
/*
draw_line(apply(matrices[0], coxeter_repelling[0]),
apply(matrices[0], coxeter_attracting[0]),
frame, "fill:none;stroke:red;stroke-width:1;");
draw_line(apply(matrices[1], coxeter_repelling[0]),
apply(matrices[1], coxeter_attracting[0]),
frame, "fill:none;stroke:red;stroke-width:1;");
draw_line(apply(matrices[2], coxeter_repelling[0]),
apply(matrices[2], coxeter_attracting[0]),
frame, "fill:none;stroke:red;stroke-width:1;");
draw_line(apply(matrices[3], coxeter_repelling[0]),
apply(matrices[3], coxeter_attracting[0]),
frame, "fill:none;stroke:red;stroke-width:1;");
draw_line(apply(matrices[4], coxeter_repelling[0]),
apply(matrices[4], coxeter_attracting[0]),
frame, "fill:none;stroke:red;stroke-width:1;");
draw_line(apply(matrices[5], coxeter_repelling[0]),
apply(matrices[5], coxeter_attracting[0]),
frame, "fill:none;stroke:red;stroke-width:1;");
draw_line(apply(matrices[14], coxeter_repelling[0]),
apply(matrices[14], coxeter_attracting[0]),
frame, "fill:none;stroke:red;stroke-width:1;");
draw_line(apply(matrices[15], coxeter_repelling[0]),
apply(matrices[15], coxeter_attracting[0]),
frame, "fill:none;stroke:red;stroke-width:1;");
draw_line(apply(matrices[22], coxeter_repelling[0]),
apply(matrices[22], coxeter_attracting[0]),
frame, "fill:none;stroke:red;stroke-width:1;");
draw_line(apply(matrices[23], coxeter_repelling[0]),
apply(matrices[23], coxeter_attracting[0]),
frame, "fill:none;stroke:red;stroke-width:1;");
*/
print_svg_footer(); print_svg_footer();
// clean up
free(group);
for(int i = 0; i < elements; i++)
gsl_matrix_free(matrices[i]);
free(matrices);
gsl_matrix_free(cartan);
gsl_matrix_free(frame);
LOOP(i) gsl_matrix_free(gen[i]);
workspace_free(ws);
for(int i = 0; i < 3*nspecial; i++) {
gsl_matrix_free(special[i]);
gsl_matrix_free(special_eigenvectors[i]);
}
free(special);
free(special_eigenvectors);
free(special_attracting);
free(special_repelling);
free(special_rotation);
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

View File

@@ -145,11 +145,11 @@ double determinant(gsl_matrix *g, workspace_t *ws)
return gsl_linalg_LU_det(ws->tmp, s); return gsl_linalg_LU_det(ws->tmp, s);
} }
void jordan_calc(gsl_matrix *g, double *evs, workspace_t *ws) int jordan_calc(gsl_matrix *g, double *evs, workspace_t *ws)
{ {
gsl_eigen_nonsymmv_params(1, ws->work_nonsymmv); gsl_eigen_nonsymmv_params(1, ws->work_nonsymmv);
gsl_eigen_nonsymmv(g, ws->eval_complex, ws->evec_complex, ws->work_nonsymmv); gsl_eigen_nonsymmv(g, ws->eval_complex, ws->evec_complex, ws->work_nonsymmv);
gsl_eigen_nonsymmv_sort(ws->eval_complex, ws->evec_complex, GSL_EIGEN_SORT_VAL_DESC); gsl_eigen_nonsymmv_sort(ws->eval_complex, ws->evec_complex, GSL_EIGEN_SORT_ABS_DESC);
int real = 1; int real = 1;
for(int i = 0; i < ws->n; i++) for(int i = 0; i < ws->n; i++)
@@ -165,9 +165,11 @@ void jordan_calc(gsl_matrix *g, double *evs, workspace_t *ws)
evs[2*i] = GSL_REAL(gsl_vector_complex_get(ws->eval_complex, i)); evs[2*i] = GSL_REAL(gsl_vector_complex_get(ws->eval_complex, i));
evs[2*i+1] = GSL_IMAG(gsl_vector_complex_get(ws->eval_complex, i)); evs[2*i+1] = GSL_IMAG(gsl_vector_complex_get(ws->eval_complex, i));
} }
return real;
} }
void eigenvectors(gsl_matrix *g, gsl_matrix *evec_real, workspace_t *ws) int eigenvectors(gsl_matrix *g, gsl_matrix *evec_real, workspace_t *ws)
{ {
gsl_matrix_memcpy(ws->stack[0], g); gsl_matrix_memcpy(ws->stack[0], g);
gsl_eigen_nonsymmv_params(0, ws->work_nonsymmv); gsl_eigen_nonsymmv_params(0, ws->work_nonsymmv);
@@ -176,20 +178,16 @@ void eigenvectors(gsl_matrix *g, gsl_matrix *evec_real, workspace_t *ws)
gsl_eigen_nonsymmv_sort(ws->eval_complex, ws->evec_complex, GSL_EIGEN_SORT_ABS_DESC); gsl_eigen_nonsymmv_sort(ws->eval_complex, ws->evec_complex, GSL_EIGEN_SORT_ABS_DESC);
int real = 1; int real = 0;
for(int j = 0; j < ws->n; j++) {
if(FCMP(GSL_IMAG(gsl_vector_complex_get(ws->eval_complex, j)), 0) == 0) {
for(int i = 0; i < ws->n; i++) for(int i = 0; i < ws->n; i++)
if(FCMP(GSL_IMAG(gsl_vector_complex_get(ws->eval_complex, i)), 0) != 0) gsl_matrix_set(evec_real, i, real, GSL_REAL(gsl_matrix_complex_get(ws->evec_complex, i, j)));
real = 0; real++;
}
if(!real) {
printf("We have non-real eigenvalues!\n");
exit(1);
} }
for(int i = 0; i < ws->n; i++) return real;
for(int j = 0; j < ws->n; j++)
gsl_matrix_set(evec_real, i, j, GSL_REAL(gsl_matrix_complex_get(ws->evec_complex, i, j)));
} }
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)

View File

@@ -38,10 +38,10 @@ void multiply_many(workspace_t *ws, gsl_matrix *out, int n, ...);
void cartan_calc(gsl_matrix *g, double *mu, workspace_t *ws); void cartan_calc(gsl_matrix *g, double *mu, workspace_t *ws);
void initialize(gsl_matrix *g, double *data, int x, int y); void initialize(gsl_matrix *g, double *data, int x, int y);
void rotation_matrix(gsl_matrix *g, double *vector); void rotation_matrix(gsl_matrix *g, double *vector);
void jordan_calc(gsl_matrix *g, double *mu, workspace_t *ws); 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);
void eigenvectors(gsl_matrix *g, gsl_matrix *evec, workspace_t *ws); int 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);

12
maketiling.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
filename="output/tiling_$1$2$3"
for i in $(seq 5 $#); do filename+="_${!i}"; done
filename_svg="${filename}.svg"
filename_pdf="${filename}.pdf"
if [ $# -lt 4 ]; then
./hyperbolic
else
./hyperbolic $* > "$filename_svg" && rsvg-convert --format=pdf "$filename_svg" > "$filename_pdf"
fi