/****************************************************************************** * Copyright (c) 2013-2015, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Texas Instruments Incorporated nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #include "cblas.h" #include "f2c.h" #include "blaswrap.h" #include "clapack.h" #ifdef __cplusplus } #endif /*----------------------------------------------------------------------------- * Timing Setup *----------------------------------------------------------------------------*/ struct timespec t0,t1; #define tick() clock_gettime(CLOCK_MONOTONIC, &t0); #define tock() (clock_gettime(CLOCK_MONOTONIC, &t1), \ t1.tv_sec - t0.tv_sec + (t1.tv_nsec - t0.tv_nsec) / 1e9) /* Auxiliary routines prototypes */ void print_eigenvalues(char * desc, int n, double * vector_r, double * vector_i); void print_eigenvectors(char * desc, int n, double * vector_i, double * v, int ldv); void form_diag_matrix(doublecomplex *matrix_diag, doublereal *vector_r, doublereal *vector_i, int n); void form_eigen_matrix(doublecomplex *mat, int n, double* vector_i, double* v, int ldv); void print_real_matrix(char* desc, doublereal *mat, int n, int m, int ldv); void print_complex_matrix(char* desc, doublecomplex *mat, int n, int m, int ldv); doublereal compute_evd_error(doublecomplex *matrix_reconstruct, doublereal *matrix_original, int n, int ld); void print_performance(char * func_name, int *matrix_sizes, float *time, int num_test, int num_run); /* Parameters */ #define MAX_ALLOWED_ERR (1e-10) /* Main program */ int print_data; int main(int argc, char *argv[]) { /* Locals */ float time, time_ev, time_cinv, *time_ev_all_runs, *time_cinv_all_runs; integer num_test, num_run, i, j, n, n_min, n_inc; integer lda, ldl, ldr, info, lwork; doublereal wkopt; doublereal* work; integer *vector_pivot, *vector_work; doublereal max_error_evd; doublereal *matrix_A, *matrix_A_cpy, *matrix_R, *matrix_L; doublereal *vector_diag, *vector_diagl, *vector_diagr, *vector_r, *vector_i; doublecomplex *matrix_D, *matrix_P, *matrix_invP, *matrix_A_cmplx, *work_dcomplex, lwork_opt; int *matrix_sizes; integer const_int6 = 6; doublereal const_dbr1 = 1.; doublereal const_dbr0 = 0.; doublecomplex const_dbc1 = {1.,0.}; doublecomplex const_dbc0 = {0.,0.}; integer rand_seed[4] = {10,123,278,3579}; /* numbers must lie between 0 and 4095 */ fprintf(stdout, "\n\n======= LAPACK example: eigen decomposition =======\n"); if(argc == 1) { /* no command line arguments, use default */ num_test = 3; n_min = 100; n_inc = 100; num_run = 1; print_data = 0; } else if (argc < 6) { printf("Usage: eig \n"); exit(0); } else { num_test = atoi(argv[1]); n_min = atoi(argv[2]); n_inc = atoi(argv[3]); num_run = atoi(argv[4]); print_data = atoi(argv[5]); } rand_seed[0] = 4675; matrix_sizes = (int*)malloc(sizeof(int)*num_test); time_ev_all_runs = (float *)malloc(sizeof(float)*num_test*num_run); time_cinv_all_runs = (float *)malloc(sizeof(float)*num_test*num_run); for(i=0, n=n_min; i 0 ) { printf("The eigen solution algorithm failed to compute eigenvalues."); printf("To generate a new matrix to test the algorithm.\n"); goto START_NEW_RUN; } printf("Eigen-decomposition finished successfully.\n"); print_eigenvalues( "Eigenvalues", n, vector_r, vector_i ); print_eigenvectors( "Right eigenvectors", n, vector_i, matrix_R, ldr ); /* Form matrix P using right eigenvectors as the columns. */ form_eigen_matrix(matrix_P, n, vector_i, matrix_R, ldr); print_complex_matrix("Eigenvector matrix P:", matrix_P, n, n, n); /* Form matrix D using eigenvalues as the diagonal elements. */ form_diag_matrix(matrix_D, vector_r, vector_i, n); print_complex_matrix("Complex diagonal matrix D: ", matrix_D, n, n, n); /* Compute inverse of P: first perform LU decomposition on P. */ printf("Compute inverse of P such that A = PDP^-1.\n"); zlacpy_("Full", &n, &n, matrix_P, &n, matrix_invP, &n); tick(); zgetrf_(&n, &n, matrix_invP, &n, vector_pivot, &info); time_cinv = tock(); /* time for complex matrix inversion */ if( info != 0 ) { printf("Return error value of zgetrf_(): %d.\n", (int)info); printf("The LU decomposition failed."); printf("To generate a new matrix to test the algorithm.\n"); goto START_NEW_RUN; } print_complex_matrix("matrix P LU decomposition results", matrix_invP, n, n, n); tick(); /* Query and allocate the optimal workspace for matrix inversion based on LU decompostion. */ lwork = -1; zgetri_(&n, matrix_invP, &n, vector_pivot, &lwork_opt, &lwork, &info); lwork = (int)lwork_opt.r; /* get optimal workspace size returned by zgetri_() */ work_dcomplex = (doublecomplex *)malloc( lwork*sizeof(doublecomplex) ); /* Compute inverse of P based on LUD results. */ zgetri_(&n, matrix_invP, &n, vector_pivot, work_dcomplex, &lwork, &info); free( (void*)work_dcomplex ); time_cinv += tock(); time_cinv_all_runs[i*num_run+j] = time_cinv; if( info != 0 ) { printf("Return error value of zgetri_(): %d.\n", (int)info); printf("Matrix P inversion through LU decomposition failed."); printf("To generate a new matrix to test the algorithm.\n"); goto START_NEW_RUN; } printf("Matrix P inversion finished successfully."); print_complex_matrix("Inverse of eigenvector matrix P:", matrix_invP, n, n, n); /* Compute P*D*inv(P). */ work_dcomplex = (doublecomplex *)malloc(sizeof(doublecomplex)*n*n); zgemm_("N", "N", &n, &n, &n, &const_dbc1, matrix_P, &n, matrix_D, &n, &const_dbc0, work_dcomplex, &n); //EDMA_Free(); matrix_A_cmplx = matrix_P; /* reuse memory */ zgemm_("N", "N", &n, &n, &n, &const_dbc1, work_dcomplex, &n, matrix_invP, &n, &const_dbc0, matrix_A_cmplx, &n); print_complex_matrix("P*D*inv(P):", matrix_A_cmplx, n, n, n); print_real_matrix("Original matrix A", matrix_A_cpy, n, n, n); /* Compute error: A-P*D*inv(P) */ max_error_evd = compute_evd_error(matrix_A_cmplx, matrix_A_cpy, n, lda); printf("\nMaximum error of EVD: %e\n", max_error_evd); if(max_error_evd > MAX_ALLOWED_ERR) { printf("Error is out of tolerance range.\n"); exit(-1); } free( (void*)work_dcomplex ); j++; START_NEW_RUN: printf("Current run finished. \n"); /* Free workspace */ __free_ddr((void *)matrix_A); __free_ddr((void *)vector_pivot); free((void *)vector_work ); free((void *)vector_diag ); free((void *)vector_diagl); free((void *)vector_diagr); __free_ddr((void *)vector_r); __free_ddr((void *)vector_i); __free_ddr((void *)matrix_L); __free_ddr((void *)matrix_R); free((void *)matrix_A_cpy); __free_ddr((void *)matrix_D); __free_ddr((void *)matrix_P); __free_ddr((void *)matrix_invP); } /* while(j= 0) { printf( " %10.5f + %10.5fi", real, imag); } else { printf( " %10.5f - %10.5fi", real, fabs(imag)); } } printf( "\n" ); } } doublereal compute_evd_error(doublecomplex *matrix_reconstruct, doublereal *matrix_original, int n, int ld) { int i, j; doublereal err_real, err_imag; doublereal abs_err; doublereal max_abs_err = 0.; for(i=0; i max_abs_err) { max_abs_err = abs_err; } } } return max_abs_err; } void print_performance(char * func_name, int *matrix_sizes, float *time, int num_test, int num_run) { int i, j; float inst, min, max; float tot, avg; printf("Time (second) of %s for all matrix sizes:\n", func_name); printf("Matrix size "); printf(" Min Max Average "); printf("\n"); for(i=0; imax) max = inst; if(inst