int fibonacci (int n) { int unit [4] = {0, 1, 1, 1}; int m [4]; if (0 == n || 1 == n) return n; matrix_power (unit, n, m); return m [1]; }
void matrix_power (int* base, int n, int* result) { int tmp [2][4]; if (1 == n) memcpy (result, base, sizeof (int) * 4); else { matrix_power (base, n / 2, tmp [0]); if (n % 2) { mul_2x2_2x2 (tmp [0], tmp [0], tmp [1]); mul_2x2_2x2 (base, tmp [1], result); } else mul_2x2_2x2 (tmp [0], tmp [0], result); } }
// exponentiate exactly a hermitian matrix "Q" into SU(NC) matrix "U" void exponentiate( GLU_complex U[ NCNC ] , const GLU_complex Q[ NCNC ] ) { #if NC == 3 GLU_real *qq = ( GLU_real* )Q ; const double REQ0 = *( qq + 0 ) ; const double REQ1 = *( qq + 2 ) ; const double IMQ1 = *( qq + 3 ) ; const double REQ2 = *( qq + 4 ) ; const double IMQ2 = *( qq + 5 ) ; const double REQ4 = *( qq + 8 ) ; const double REQ5 = *( qq + 10 ) ; const double IMQ5 = *( qq + 11 ) ; const double REQ8 = *( qq + 16 ) ; // speed this up too (use determinant relation) const double c1 = ( REQ0 * REQ0 + REQ0 * REQ4 + REQ4 * REQ4 \ + REQ1 * REQ1 + IMQ1 * IMQ1 \ + REQ2 * REQ2 + IMQ2 * IMQ2 \ + REQ5 * REQ5 + IMQ5 * IMQ5 ) * OneO3 ; //Iff c0_max < ( smallest representable double) the matrix Q is zero and its //exponential is the identity matrix .. if( unlikely( c1 < DBL_MIN ) ) { *( U + 0 ) = 1. ; *( U + 1 ) = 0. ; *( U + 2 ) = 0. ; *( U + 3 ) = 0. ; *( U + 4 ) = 1. ; *( U + 5 ) = 0. ; *( U + 6 ) = 0. ; *( U + 7 ) = 0. ; *( U + 8 ) = 1. ; return ; } // will write this out as it can be done cheaper // 1/3 * tr AAA is just det( A ) // Below is a quickened determinant double c0 = REQ0 * ( REQ4 * REQ8 \ - REQ5 * REQ5 - IMQ5 * IMQ5 ) ; // from the middle c0 -= REQ1 * ( REQ1 * REQ8 \ - REQ5 * REQ2 - IMQ5 * IMQ2 ) ; c0 += IMQ1 * ( - IMQ1 * REQ8 \ + REQ5 * IMQ2 - IMQ5 * REQ2 ) ; // final column c0 += REQ2 * ( - REQ4 * REQ2 \ + REQ1 * REQ5 - IMQ1 * IMQ5 ) ; c0 -= IMQ2 * ( REQ4 * IMQ2 \ - REQ1 * IMQ5 - IMQ1 * REQ5 ) ; // so if c0 is negative we flip the sign ... const double flag = c0 < 0 ? -1.0 : 1.0 ; c0 *= flag ; // compute the constants c0_max and the root of c1 ... const double rc1 = sqrt( c1 ) ; const double c0_max = 2. * rc1 * c1 ; const double theta = acos( c0 / c0_max ) * OneO3 ; const double ctheta = cos( theta ) ; register const double u = rc1 * ctheta ; register const double w = r3 * rc1 * sin( theta ) ; const double uu = u * u , ww = w * w , cw = cos( w ) ; const double denom = 1.0 / ( 9. * uu - ww ) ; const double cu = cos( u ) ; const double su = sin( u ) ; // and I thought double angle formulas were useless! //double complex one , two ; const double complex one = cu - I * su ; double complex two = conj( one ) ; //cu + I * su ; two *= two ; // taylor expand if getting toward the numerically unstable end const double E0 = fabs( w ) < SINTOL ? ( 1 - ww / 6. * ( 1 - ww / 20. * ( 1 - ww / 42. ) ) ) : sin( w ) / w ; double complex f0 = ( uu - ww ) * two + one * ( 8. * uu * cw + 2. * I * u * ( 3. * uu + ww ) * E0 ) ; double complex f1 = 2. * u * two - one * ( 2. * u * cw - I * ( 3. * uu - ww ) * E0 ) ; double complex f2 = two - one * ( cw + 3. * I * u * E0 ) ; f0 = denom * ( creal( f0 ) + I * cimag( f0 ) * flag ) ; f1 = denom * ( flag * creal( f1 ) + I * cimag( f1 ) ) ; f2 = denom * ( creal( f2 ) + I * cimag( f2 ) * flag ) ; // QQ[0]. const double temp0 = REQ0 * REQ0 + REQ1 * REQ1 + \ IMQ1 * IMQ1 + REQ2 * REQ2 + IMQ2 * IMQ2 ; // QQ[1] const double complex temp1 = -REQ1 * ( REQ8 ) + REQ2 * REQ5 + IMQ2 * IMQ5 + I * ( REQ5 * IMQ2 - REQ2 * IMQ5 - IMQ1 * REQ8 ) ; // QQ[2] const double complex temp2 = REQ1 * REQ5 - IMQ1 * IMQ5 - REQ2 * REQ4 + I * ( IMQ1 * REQ5 + IMQ5 * REQ1 - IMQ2 * REQ4 ) ; // QQ[4] const double temp3 = REQ4 * REQ4 + REQ1 * REQ1 \ + IMQ1 * IMQ1 + REQ5 * REQ5 + IMQ5 * IMQ5 ; // QQ[5] const double complex temp4 = REQ1 * REQ2 + IMQ2 * IMQ1 - REQ0 * REQ5 + I * ( REQ1 * IMQ2 - REQ2 * IMQ1 - REQ0 * IMQ5 ) ; // QQ[8] const double temp5 = REQ8 * REQ8 + REQ2 * REQ2 + \ IMQ2 * IMQ2 + REQ5 * REQ5 + IMQ5 * IMQ5 ; // U = f0I + f1 Q + f2 QQ *( U + 0 ) = f0 + f1 * REQ0 + f2 * temp0 ; *( U + 1 ) = f1 * Q[1] + f2 * temp1 ; *( U + 2 ) = f1 * Q[2] + f2 * temp2 ; // *( U + 3 ) = f1 * Q[3] + f2 * conj( temp1 ) ; *( U + 4 ) = f0 + f1 * REQ4 + f2 * temp3 ; *( U + 5 ) = f1 * Q[5] + f2 * temp4 ; // *( U + 6 ) = f1 * Q[6] + f2 * conj( temp2 ) ; *( U + 7 ) = f1 * Q[7] + f2 * conj( temp4 ) ; *( U + 8 ) = f0 + f1 * REQ8 + f2 * temp5 ; #elif NC == 2 double f0 , f1 ; // f1 is purely imaginary // eigenvalues are pretty simple +/- sqrt( |a|^2 + |b|^2 ) Only need one const double z = sqrt( creal( Q[0] ) * creal( Q[0] ) + \ creal( Q[1] ) * creal( Q[1] ) + \ cimag( Q[1] ) * cimag( Q[1] ) ) ; // have eigenvalues, now for the "fun" bit. f0 = cos( z ) ; // taylor expand f1 = fabs ( z ) < SINTOLSU2 ? ( 1 - z / 6. * ( 1 - z / 20. * ( 1 - z / 42. ) ) ) : sin( z ) / z ; const double complex f1Q0 = I * f1 * creal( Q[0] ) ; const double complex f1Q1 = I * f1 * Q[1] ; *( U + 0 ) = (GLU_complex)( f0 + f1Q0 ) ; *( U + 1 ) = (GLU_complex)( f1Q1 ) ; *( U + 2 ) = (GLU_complex)( -conj( f1Q1 ) ) ; *( U + 3 ) = (GLU_complex)( f0 - f1Q0 ) ; #else // hmmm could be a toughy #if ( defined HAVE_LAPACKE_H || defined HAVE_GSL ) double complex f[ NC ] ; double z[ NC ] ; Eigenvalues_hermitian( z , Q ) ; calculate_effs_VDM_herm( f , z ) ; // matrix expansion reversing horner's rule int i , j ; diag( U , f[ NC - 1 ] ) ; for( i = NC-1 ; i > 0 ; i-- ) { multab_atomic_left( U , Q ) ; // left multiply U with Q for( j = 0 ; j < NC ; j++ ) { U[ j*(NC+1) ] += f[ i-1 ] ; } } #else // exponentiate routine from stephan durr's paper // Performs the nesting // U = ( exp{ A / DIV^n ) ) ^ ( DIV * n ) GLU_complex EOLD[ NCNC ] GLUalign , SN[ NCNC ] GLUalign ; GLU_complex RN_MIN[ NCNC ] GLUalign , RN[ NCNC ] GLUalign ; // set to zero zero_mat( EOLD ) ; // set up the divisor and the minimum double sum = 0.0 ; size_t j , n ; const int nmin = 3 ; // use precomputed factorials for( n = nmin ; n < 10 ; n++ ) { // compute the multiplicative factor ... const int iter = 2 << ( n - 1 ) ; const GLU_complex fact = I / (GLU_real)iter ; // and the rational approximations #ifdef USE_PADE for( j = 0 ; j < NCNC ; j++ ) { SN[ j ] = ( Q[j] * fact ) ; } horners_pade( RN , SN ) ; for( j = 0 ; j < NCNC ; j++ ) { SN[ j ] *= -1.0 ; } horners_pade( RN_MIN , SN ) ; #else for( j = 0 ; j < NCNC ; j++ ) { SN[ j ] = ( Q[j] * fact ) / 2.0 ; } horners_exp( RN , SN , 14 ) ; for( j = 0 ; j < NCNC ; j++ ) { SN[ j ] *= -1.0 ; } horners_exp( RN_MIN , SN , 14 ) ; #endif inverse( SN , RN_MIN ) ; // uses our numerical inverse multab_atomic_right( RN , SN ) ; // gets the correct rational approx // and remove the nested scalings ... matrix_power( U , RN , iter ) ; // uses a fast-power like routine // for the convergence criteria, I use the absolute difference between // evaluations sum = 0.0 ; for( j = 0 ; j < NCNC ; j++ ) { sum += (double)cabs( EOLD[j] - U[j] ) ; EOLD[ j ] = U[ j ] ; } sum /= NCNC ; // convergence .... if( sum < PREC_TOL ) { break ; } // warning for non-convergence .. if( n >= ( MAX_FACTORIAL - 1 ) ) { printf( "[EXPONENTIAL] not converging .. %zu %e \n" , n , sum ) ; break ; } } // gramschmidt orthogonalisation just to make sure // has been seen to help preserve gauge invariance of log smearing gram_reunit( U ) ; #endif #endif return ; }
void operator_matrix() { matrix result; char in[USHRT_MAX]; int m; int n; while (1) { printf("Entre com o número de linhas da 1ª matriz: "); scanf("%s", in); m = atoi(in); printf("\n"); if (m == 0) printf("Valor inválido!\n\n"); else break; } while (1) { printf("Entre com o número de colunas da 1ª matriz: "); scanf("%s", in); n = atoi(in); printf("\n"); if (n == 0) printf("Valor inválido!\n\n"); else break; } result = matrix_constructor(m, n); printf("Entre com os elementos da 1ª matriz, separando-os por espaços e/ou quebras de linha:\n"); for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) { scanf("%s", in); result.table[i][j] = atof(in); } printf("\n"); int keep_going = 1; while (keep_going) { matrix next; switch (menu_matrix()) { case 1: // Add while (1) { while (1) { printf("Entre com o número de linhas da proxima matriz: "); scanf("%s", in); m = atoi(in); printf("\n"); if (m == 0) printf("Valor inválido!\n\n"); else break; } while (1) { printf("Entre com o número de colunas da proxima matriz: "); scanf("%s", in); n = atoi(in); printf("\n"); if (n == 0) printf("Valor inválido!\n\n"); else break; } next = matrix_constructor(m, n); if (!matrix_can_add(result, next)) printf("Não é possivel fazer a operação desejada com as matrizes de ordens previamente informadas!\n\n"); else break; } printf("Entre com os elementos da proxima matriz, separando-os por espaços e/ou quebras de linha:\n"); for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) { scanf("%s", in); next.table[i][j] = atof(in); } printf("\n"); matrix_add(&result, next); break; case 2: // Subtract while (1) { while (1) { printf("Entre com o número de linhas da proxima matriz: "); scanf("%s", in); m = atoi(in); printf("\n"); if (m == 0) printf("Valor inválido!\n\n"); else break; } while (1) { printf("Entre com o número de colunas da proxima matriz: "); scanf("%s", in); n = atoi(in); printf("\n"); if (n == 0) printf("Valor inválido!\n\n"); else break; } next = matrix_constructor(m, n); if (!matrix_can_subtract(result, next)) printf("Não é possivel fazer a operação desejada com as matrizes de ordens previamente informadas!\n\n"); else break; } printf("Entre com os elementos da proxima matriz, separando-os por espaços e/ou quebras de linha:\n"); for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) { scanf("%s", in); next.table[i][j] = atof(in); } printf("\n"); matrix_subtract(&result, next); break; case 3: // Multiply while (1) { while (1) { printf("Entre com o número de linhas da proxima matriz: "); scanf("%s", in); m = atoi(in); printf("\n"); if (m == 0) printf("Valor inválido!\n\n"); else break; } while (1) { printf("Entre com o número de colunas da proxima matriz: "); scanf("%s", in); n = atoi(in); printf("\n"); if (n == 0) printf("Valor inválido!\n\n"); else break; } next = matrix_constructor(m, n); if (!matrix_can_multiply(result, next)) printf("Não é possivel fazer a operação desejada com as matrizes de ordens previamente informadas!\n\n"); else break; } printf("Entre com os elementos da proxima matriz, separando-os por espaços e/ou quebras de linha:\n"); for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) { scanf("%s", in); next.table[i][j] = atof(in); } printf("\n"); matrix_multiply(&result, next); break; case 4: // Power if (matrix_can_power(result)) { while (1) { printf("Entre com o próximo valor: "); scanf("%s", in); printf("\n"); if (atoll(in) >= 0) { matrix_power(&result, (unsigned long long int) atoll(in)); break; } else printf("Valor inválido!\n\n"); } } else printf("Não é possivel realizar a operação desejada com a matrix atual!\n\n"); break; default: keep_going = 0; break; } matrix_destructor(&next); printf("Resultado:\n\n"); matrix_print(result); printf("\n"); if (!keep_going) matrix_destructor(&result); } }