2020-08-02 22:48:33 +00:00
# include "coxeter.h"
2021-10-23 17:09:40 +00:00
# include "linalg.h"
2020-07-02 02:26:42 +00:00
# include "mat.h"
2021-10-23 21:04:12 +00:00
# include "enumerate_triangle_group.h"
2021-10-23 17:09:40 +00:00
2022-02-05 23:51:45 +00:00
# include <time.h>
2020-07-30 00:23:15 +00:00
# define SWAP(t,x,y) do { t _tmp = (x); (x) = (y); (y) = _tmp; } while (0);
2022-02-05 23:51:45 +00:00
# define DEBUG(msg, ...) fprintf(stderr, "[%10.3f] " msg, runtime(), ##__VA_ARGS__);
//#define DEBUG(msg, ...)
2021-10-01 18:36:56 +00:00
struct result {
2021-10-23 17:09:40 +00:00
int id ;
int count ;
2021-10-01 18:36:56 +00:00
mpq_t tr ;
mpq_t trinv ;
2021-10-23 17:09:40 +00:00
double x ;
double y ;
2021-10-01 18:36:56 +00:00
} ;
2021-10-23 17:09:40 +00:00
static int compare_result ( const void * a_ , const void * b_ )
2021-04-01 03:45:25 +00:00
{
2021-10-23 17:09:40 +00:00
int d = 0 ;
2021-04-01 03:45:25 +00:00
2021-10-23 17:09:40 +00:00
struct result * * a = ( struct result * * ) a_ ;
struct result * * b = ( struct result * * ) b_ ;
2021-04-01 03:45:25 +00:00
2021-10-23 17:09:40 +00:00
d = mpq_cmp ( ( * a ) - > tr , ( * b ) - > tr ) ;
if ( d = = 0 ) {
d = mpq_cmp ( ( * a ) - > trinv , ( * b ) - > trinv ) ;
}
2021-04-01 03:45:25 +00:00
2021-10-23 17:09:40 +00:00
return d ;
2021-04-01 03:45:25 +00:00
}
2022-02-05 23:51:45 +00:00
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_ )
2021-10-01 18:36:56 +00:00
{
2021-10-23 17:09:40 +00:00
int d = 0 ;
2020-08-10 18:00:52 +00:00
2021-10-23 17:09:40 +00:00
struct result * * a = ( struct result * * ) a_ ;
struct result * * b = ( struct result * * ) b_ ;
2021-10-01 18:36:56 +00:00
2021-10-23 17:09:40 +00:00
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 ;
}
2021-10-01 18:36:56 +00:00
}
2021-10-23 17:09:40 +00:00
return d ;
2021-10-01 18:36:56 +00:00
}
2020-08-02 22:48:33 +00:00
2021-10-23 17:09:40 +00:00
static int compare_result_by_slope ( const void * a_ , const void * b_ )
2020-08-02 22:48:33 +00:00
{
int d = 0 ;
struct result * * a = ( struct result * * ) a_ ;
struct result * * b = ( struct result * * ) b_ ;
2021-10-23 17:09:40 +00:00
double slopea = ( * a ) - > x / ( * a ) - > y ;
double slopeb = ( * b ) - > x / ( * b ) - > y ;
2020-08-02 22:48:33 +00:00
2021-10-23 17:09:40 +00:00
return slopea > slopeb ? - 1 : slopea < slopeb ? 1 : 0 ;
2020-08-02 22:48:33 +00:00
}
2020-07-30 00:23:15 +00:00
2022-02-05 23:51:45 +00:00
struct timespec starttime ;
static void start_timer ( )
2021-10-23 17:09:40 +00:00
{
2022-02-05 23:51:45 +00:00
clock_gettime ( CLOCK_MONOTONIC , & starttime ) ;
}
static double runtime ( )
{
struct timespec curtime ;
double diff ;
clock_gettime ( CLOCK_MONOTONIC , & curtime ) ;
return ( curtime . tv_sec - starttime . tv_sec ) + ( curtime . tv_nsec - starttime . tv_nsec ) / 1e9 ;
}
int compute_invariants ( group_t * group , mat * matrices , struct result * * invariants , int * n , int unique )
{
mpq_t tmp ;
2021-10-23 17:09:40 +00:00
mps_context * solver ;
2022-02-05 23:51:45 +00:00
mps_monomial_poly * poly ;
int index ;
int ntraces = * n , nuniq ;
2021-10-23 17:09:40 +00:00
int retval ;
double evs [ 3 ] ;
2022-02-05 23:51:45 +00:00
int max_slope_id ;
2021-10-23 17:09:40 +00:00
double max_slope ;
char buf [ 100 ] ;
2022-02-05 23:51:45 +00:00
// 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 ] ) ;
2021-10-01 18:36:56 +00:00
}
2020-08-02 22:48:33 +00:00
2022-02-05 23:51:45 +00:00
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 ] ;
invariants [ nuniq ] - > count = 1 ;
nuniq + + ;
} else {
invariants [ nuniq - 1 ] - > count + + ;
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 ;
}
}
2021-10-23 17:09:40 +00:00
}
2020-07-02 02:26:42 +00:00
2022-02-05 23:51:45 +00:00
DEBUG ( " Solve characteristic polynomials \n " ) ;
2021-10-23 17:09:40 +00:00
solver = mps_context_new ( ) ;
2022-02-05 23:51:45 +00:00
poly = mps_monomial_poly_new ( solver , 3 ) ;
2021-10-23 17:09:40 +00:00
mps_context_set_output_prec ( solver , 20 ) ; // relative precision
mps_context_set_output_goal ( solver , MPS_OUTPUT_GOAL_APPROXIMATE ) ;
2020-07-02 02:26:42 +00:00
2021-10-23 17:09:40 +00:00
max_slope = 0 ;
for ( int i = 0 ; i < nuniq ; i + + ) {
2022-02-05 23:51:45 +00:00
retval = solve_characteristic_polynomial ( solver , poly , invariants [ i ] - > tr , invariants [ i ] - > trinv , evs ) ;
retval = 0 ; evs [ 0 ] = 2 ; evs [ 1 ] = 1 ; evs [ 2 ] = 0.5 ; // fake solving the polynomial for memory leak test
2021-10-23 17:09:40 +00:00
if ( retval = = 1 ) {
fprintf ( stderr , " Error! Could not solve polynomial. \n " ) ;
continue ;
} else if ( retval = = 2 ) {
continue ;
2021-10-01 18:36:56 +00:00
}
2021-04-01 03:45:25 +00:00
2021-10-23 17:09:40 +00:00
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 ] ) ;
2021-04-01 03:45:25 +00:00
2021-10-23 17:09:40 +00:00
double x = log ( fabs ( evs [ 0 ] ) ) ;
double y = - log ( fabs ( evs [ 2 ] ) ) ;
2021-10-01 18:36:56 +00:00
2022-02-05 23:51:45 +00:00
invariants [ i ] - > x = x ;
invariants [ i ] - > y = y ;
2020-08-02 22:48:33 +00:00
2022-02-05 23:51:45 +00:00
if ( y / x > max_slope + 1e-12 & & ( x > 0.1 | | y > 0.1 ) ) {
max_slope_id = invariants [ i ] - > id ;
2021-10-23 17:09:40 +00:00
max_slope = y / x ;
2022-02-05 23:51:45 +00:00
} else if ( y / x > max_slope - 1e-12 & & ( x > 0.1 | | y > 0.1 ) ) {
// DEBUG("%s didn't quite make it\n",
// print_word(&group->elements[invariants[i]->id], buf));
2021-10-23 17:09:40 +00:00
}
}
2022-02-05 23:51:45 +00:00
mps_context_free ( solver ) ;
2021-10-01 18:36:56 +00:00
2022-02-05 23:51:45 +00:00
qsort ( invariants , nuniq , sizeof ( struct result * ) , compare_result_by_id ) ;
2021-10-01 18:36:56 +00:00
2022-02-05 23:51:45 +00:00
* n = nuniq ;
return max_slope_id ;
}
2021-10-23 21:04:12 +00:00
2022-02-05 23:51:45 +00:00
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 ;
}
int main ( int argc , char * argv [ ] )
{
mpq_t s , q , t , tmp ;
int p1 , p2 , p3 ;
int sstart , send , sdenom , qstart , qend , qdenom ;
mat * matrices ;
group_t * group ;
int nmax , n ;
int max_slope_id ;
char buf [ 100 ] ;
char buf2 [ 100 ] ;
struct result * invariants ;
struct result * * distinct_invariants ;
start_timer ( ) ;
mpq_inits ( s , q , t , tmp , NULL ) ;
if ( argc < 11 ) {
fprintf ( stderr , " Usage: %s <N> <p1> <p2> <p3> <s start> <s end> <s denom> <q start> <q end> <q denom> \n " , argv [ 0 ] ) ;
exit ( 1 ) ;
}
nmax = atoi ( argv [ 1 ] ) ;
p1 = atoi ( argv [ 2 ] ) ;
p2 = atoi ( argv [ 3 ] ) ;
p3 = atoi ( argv [ 4 ] ) ;
sstart = atoi ( argv [ 5 ] ) ;
send = atoi ( argv [ 6 ] ) ;
sdenom = atoi ( argv [ 7 ] ) ;
qstart = atoi ( argv [ 8 ] ) ;
qend = atoi ( argv [ 9 ] ) ;
qdenom = atoi ( argv [ 10 ] ) ;
DEBUG ( " Allocate \n " ) ;
matrices = malloc ( nmax * sizeof ( mat ) ) ;
for ( int i = 0 ; i < nmax ; i + + )
mat_init ( matrices [ i ] , 3 ) ;
invariants = malloc ( nmax * sizeof ( struct result ) ) ;
distinct_invariants = malloc ( nmax * sizeof ( struct result ) ) ;
for ( int i = 0 ; i < nmax ; i + + ) {
mpq_init ( invariants [ i ] . tr ) ;
mpq_init ( invariants [ i ] . trinv ) ;
}
// order of the triangle reflection generators: a, b, c
// order of the rotation orders: bc, ac, ab
DEBUG ( " Generate group \n " ) ;
group = coxeter_init_triangle ( p1 , p2 , p3 , nmax ) ;
// first run; compute all matrices
for ( int i = 0 ; i < group - > size ; i + + )
group - > elements [ i ] . need_to_compute = 1 ;
// use very generic values for the pilot run unless sstart=send and qstart=qend
if ( sstart = = send & & qstart = = qend ) {
mpq_set_ui ( s , sstart , sdenom ) ;
mpq_set_ui ( q , qstart , qdenom ) ;
DEBUG ( " Single run for s = %d/%d, q = %d/%d \n " , sstart , sdenom , qstart , qdenom ) ;
} else {
mpq_set_ui ( s , 4 , 100 ) ;
mpq_set_ui ( q , 7 , 100 ) ;
DEBUG ( " Initial run for s = %d/%d, q = %d/%d \n " , 4 , 100 , 7 , 100 ) ;
}
DEBUG ( " Compute matrices \n " ) ;
enumerate ( group , matrices , p1 , p2 , p3 , s , q ) ;
2021-10-01 18:36:56 +00:00
2022-02-05 23:51:45 +00:00
// prepare array of ids
n = 0 ;
for ( int i = 0 ; i < group - > size ; i + + )
{
if ( group - > elements [ i ] . length % 2 ! = 0 | | ! group - > elements [ i ] . inverse )
2021-10-23 17:09:40 +00:00
continue ;
2022-02-05 23:51:45 +00:00
invariants [ i ] . id = i ;
distinct_invariants [ n + + ] = & invariants [ i ] ;
}
DEBUG ( " Compute invariants \n " ) ;
max_slope_id = compute_invariants ( group , matrices , distinct_invariants , & n , 1 ) ;
// prepare for next time; don't need to change ids in distinct_invariants!
for ( int i = 0 ; i < group - > size ; i + + )
group - > elements [ i ] . need_to_compute = 0 ;
group - > elements [ 0 ] . need_to_compute = 1 ;
int multiplication_count = 1 ;
for ( int i = 0 ; i < n ; i + + ) {
groupelement_t * cur = & group - > elements [ distinct_invariants [ i ] - > id ] ;
while ( cur - > need_to_compute = = 0 ) {
cur - > need_to_compute = 1 ;
multiplication_count + + ;
cur = cur - > parent - > parent ; // also need to compute its even-length ancestors
2021-04-01 03:45:25 +00:00
}
2022-02-05 23:51:45 +00:00
cur = group - > elements [ distinct_invariants [ i ] - > id ] . inverse ;
while ( cur - > need_to_compute = = 0 ) {
cur - > need_to_compute = 1 ;
multiplication_count + + ;
cur = cur - > parent - > parent ;
2021-10-23 17:09:40 +00:00
}
2022-02-05 23:51:45 +00:00
}
DEBUG ( " Would have needed %d matrix multiplications for %d unique traces up to reflection length %d \n " , multiplication_count , n , group - > elements [ group - > size - 1 ] . length ) ;
if ( sstart ! = send | | qstart ! = qend ) {
for ( int sloop = sstart ; sloop < = send ; sloop + + ) {
for ( int qloop = qstart ; qloop < = qend ; qloop + + ) {
DEBUG ( " Loop for s = %d/%d, q = %d/%d \n " , sloop , sdenom , qloop , qdenom ) ;
mpq_set_ui ( s , sloop , sdenom ) ;
mpq_set_ui ( q , qloop , qdenom ) ;
DEBUG ( " Compute matrices \n " ) ;
enumerate ( group , matrices , p1 , p2 , p3 , s , q ) ;
DEBUG ( " Compute invariants \n " ) ;
max_slope_id = compute_invariants ( group , matrices , distinct_invariants , & n , 0 ) ;
// output
gmp_printf ( " %Qd %Qd %s \n " , s , q ,
print_word ( & group - > elements [ max_slope_id ] , buf ) ) ;
fflush ( stdout ) ;
}
2021-10-23 17:09:40 +00:00
}
2022-02-05 23:51:45 +00:00
} else {
// output
for ( int i = 0 ; i < n ; i + + ) {
double slope = distinct_invariants [ i ] - > y / distinct_invariants [ i ] - > x ;
// exclude tr = trinv = 2/1/0/-1/3
mpq_set_si ( tmp , 2 , 1 ) ;
if ( mpq_cmp ( distinct_invariants [ i ] - > tr , tmp ) = = 0 & &
mpq_cmp ( distinct_invariants [ i ] - > trinv , tmp ) = = 0 )
continue ;
mpq_set_si ( tmp , 1 , 1 ) ;
if ( mpq_cmp ( distinct_invariants [ i ] - > tr , tmp ) = = 0 & &
mpq_cmp ( distinct_invariants [ i ] - > trinv , tmp ) = = 0 )
continue ;
mpq_set_si ( tmp , 0 , 1 ) ;
if ( mpq_cmp ( distinct_invariants [ i ] - > tr , tmp ) = = 0 & &
mpq_cmp ( distinct_invariants [ i ] - > trinv , tmp ) = = 0 )
continue ;
mpq_set_si ( tmp , - 1 , 1 ) ;
if ( mpq_cmp ( distinct_invariants [ i ] - > tr , tmp ) = = 0 & &
mpq_cmp ( distinct_invariants [ i ] - > trinv , tmp ) = = 0 )
continue ;
mpq_set_si ( tmp , 3 , 1 ) ;
if ( mpq_cmp ( distinct_invariants [ i ] - > tr , tmp ) = = 0 & &
mpq_cmp ( distinct_invariants [ i ] - > trinv , tmp ) = = 0 )
continue ;
gmp_printf ( " %d %d %s %f \n " ,
distinct_invariants [ i ] - > id , distinct_invariants [ i ] - > count ,
print_word ( & group - > elements [ distinct_invariants [ i ] - > id ] , buf ) ,
slope
) ;
/*
gmp_printf ( " %d %d %d %Qd %Qd %f %f %f %f %f %s \n " ,
distinct_invariants [ i ] - > id , distinct_invariants [ i ] - > count , cumulative ,
distinct_invariants [ i ] - > tr , distinct_invariants [ i ] - > trinv ,
log ( fabs ( mpq_get_d ( distinct_invariants [ i ] - > tr ) ) ) , log ( fabs ( mpq_get_d ( distinct_invariants [ i ] - > trinv ) ) ) ,
distinct_invariants [ i ] - > x , distinct_invariants [ i ] - > y , slope ,
print_word ( & group - > elements [ distinct_invariants [ i ] - > id ] , buf )
) ;
*/
2021-10-23 17:09:40 +00:00
}
2021-04-01 03:45:25 +00:00
}
2021-10-23 17:09:40 +00:00
DEBUG ( " Clean up \n " ) ;
for ( int i = 0 ; i < nmax ; i + + ) {
mpq_clear ( invariants [ i ] . tr ) ;
mpq_clear ( invariants [ i ] . trinv ) ;
}
free ( invariants ) ;
free ( distinct_invariants ) ;
for ( int i = 0 ; i < nmax ; i + + )
mat_clear ( matrices [ i ] ) ;
free ( matrices ) ;
coxeter_clear ( group ) ;
mpq_clears ( s , q , t , tmp , NULL ) ;
2020-07-01 14:59:16 +00:00
}