# include # include # include # include # include # include "hankel_cholesky.h" /******************************************************************************/ double *hankel_cholesky_upper ( int n, double h[] ) /******************************************************************************/ /* Purpose: HANKEL_CHOLESKY_UPPER computes the upper Cholesky factor of a Hankel matrix. Licensing: This code is distributed under the MIT license. Modified: 30 January 2017 Author: John Burkardt Reference: James Phillips, The triangular decomposition of Hankel matrices, Mathematics of Computation, Volume 25, Number 115, July 1971, pages 599-602. Parameters: Input, int N, the order of the matrix. Input, double H[2*N-1], the values defining the antidiagonals. Output, double HANKEL_CHOLESKY_UPPER[N*N], the upper triangular Cholesky factor. */ { double a; double b; double *c; int i; int j; double *r; double t; c = ( double * ) malloc ( ( 2 * n - 1 ) * ( 2 * n - 1 ) * sizeof ( double ) ); for ( j = 0; j < 2 * n - 1; j++ ) { c[0+j*(2*n-1)] = h[j]; } for ( i = 0; i < n - 1; i++ ) { if ( i == 0 ) { a = c[0+1*(2*n-1)] / c[0+0*(2*n-1)]; b = 0.0; } else { a = c[i+(i+1)*(2*n-1)] / c[i+i*(2*n-1)] - c[i-1+i*(2*n-1)] / c[i-1+(i-1)*(2*n-1)]; b = c[i+i*(2*n-1)] / c[i-1+(i-1)*(2*n-1)]; } for ( j = i + 1; j < 2 * n - i - 2; j++ ) { c[i+1+j*(2*n-1)] = c[i+(j+1)*(2*n-1)] - a * c[i+j*(2*n-1)]; if ( 0 < i ) { c[i+1+j*(2*n-1)] = c[i+1+j*(2*n-1)] - b * c[i-1+j*(2*n-1)]; } } } r = ( double * ) malloc ( n * n * sizeof ( double ) ); for ( j = 0; j < n; j++ ) { for ( i = 0; i < n; i++ ) { r[i+j*n] = c[i+j*(2*n-1)]; } } /* Normalize. This will fail if H is not positive definite. */ for ( i = 0; i < n; i++ ) { t = sqrt ( r[i+i*n] ); for ( j = 0; j < i; j++ ) { r[i+j*n] = 0.0; } for ( j = i; j < n; j++ ) { r[i+j*n] = r[i+j*n] / t; } } free ( c ); return r; } /******************************************************************************/ double *hankel_pds_cholesky_lower ( int n, double lii[], double liim1[] ) /******************************************************************************/ /* Purpose: HANKEL_PDS_CHOLESKY_LOWER returns L such that L*L' is Hankel PDS. Discussion: In other words, H = L * L' is a positive definite symmetric matrix with the property that H is constant along antidiagonals, so that H(I+J) = h(k-1), for 1 <= I, J <= N, 1 <= K <= 2*N-1. Licensing: This code is distributed under the MIT license. Modified: 27 January 2017 Author: S Al-Homidan, M Alshahrani. C implementation by John Burkardt. Reference: S Al-Homidan, M Alshahrani, Positive Definite Hankel Matrices Using Cholesky Factorization, Computational Methods in Applied Mathematics, Volume 9, Number 3, pages 221-225, 2009. Parameters: Input, int N, the order of the matrix. Input, double LII[N], values to be used in L(I,I), for 1 <= I <= N. Input, double LIIM1[N-1], values to be used in L(I+1,I) for 1 <= I <= N-1. Output, double HANKEL_PDS_CHOLESKY_LOWER[N,N], the lower Cholesky factor. */ { double alpha; double beta; int i; int j; double *l; int q; int r; int s; int t; l = r8mat_zeros_new ( n, n ); for ( i = 0; i < n; i++ ) { l[i+i*n] = lii[i]; } for ( i = 0; i < n - 1; i++ ) { l[i+1+i*n] = liim1[i]; } for ( i = 2; i < n; i++ ) { for ( j = 0; j < i - 1; j++ ) { if ( ( ( i + j ) % 2 ) == 0 ) { q = ( i + j ) / 2; r = q; } else { q = ( i + j - 1 ) / 2; r = q + 1; } alpha = 0.0; for ( s = 0; s <= q; s++ ) { alpha = alpha + l[q+s*n] * l[r+s*n]; } beta = 0.0; for ( t = 0; t < j; t++ ) { beta = beta + l[i+t*n] * l[j+t*n]; } l[i+j*n] = ( alpha - beta ) / l[j+j*n]; } } return l; } /******************************************************************************/ double *r8mat_cholesky_factor ( int n, double a[], int *flag ) /******************************************************************************/ /* Purpose: R8MAT_CHOLESKY_FACTOR computes the Cholesky factor of a symmetric R8MAT. Discussion: An R8MAT is a doubly dimensioned array of R8 values, stored as a vector in column-major order. The matrix must be symmetric and positive semidefinite. For a positive semidefinite symmetric matrix A, the Cholesky factorization is a lower triangular matrix L such that: A = L * L' Licensing: This code is distributed under the MIT license. Modified: 11 November 2012 Author: John Burkardt Parameters: Input, int N, the number of rows and columns of the matrix A. Input, double A[N*N], the N by N matrix. Output, int *FLAG, an error flag. 0, no error was detected. 1, the matrix is not positive definite. 2, the matrix is not nonnegative definite. Output, double R8MAT_CHOLESKY_FACTOR[N*N], the N by N lower triangular Cholesky factor. */ { double *c; int i; int j; int k; double sum2; double tol; *flag = 0; tol = sqrt ( DBL_EPSILON ); c = r8mat_copy_new ( n, n, a ); for ( j = 0; j < n; j++ ) { for ( i = 0; i < j; i++ ) { c[i+j*n] = 0.0; } for ( i = j; i < n; i++ ) { sum2 = c[j+i*n]; for ( k = 0; k < j; k++ ) { sum2 = sum2 - c[j+k*n] * c[i+k*n]; } if ( i == j ) { if ( 0.0 < sum2 ) { c[i+j*n] = sqrt ( sum2 ); } else if ( sum2 < - tol ) { *flag = 2; fprintf ( stderr, "\n" ); fprintf ( stderr, "R8MAT_CHOLESKY_FACTOR - Fatal error!\n" ); fprintf ( stderr, " Matrix is not nonnegative definite.\n" ); fprintf ( stderr, " Diagonal I = %d\n", i ); fprintf ( stderr, " SUM2 = %g\n", sum2 ); exit ( 1 ); } else { *flag = 1; c[i+j*n] = 0.0; } } else { if ( c[j+j*n] != 0.0 ) { c[i+j*n] = sum2 / c[j+j*n]; } else { c[i+j*n] = 0.0; } } } } return c; } /******************************************************************************/ double *r8mat_cholesky_factor_upper ( int n, double a[], int *flag ) /******************************************************************************/ /* Purpose: R8MAT_CHOLESKY_FACTOR_UPPER: upper Cholesky factor of a symmetric R8MAT. Discussion: An R8MAT is a doubly dimensioned array of R8 values, stored as a vector in column-major order. The matrix must be symmetric and positive semidefinite. For a positive semidefinite symmetric matrix A, the Cholesky factorization is an upper triangular matrix R such that: A = R' * R Note that the usual Cholesky factor is a LOWER triangular matrix L such that A = L * L' Licensing: This code is distributed under the MIT license. Modified: 03 August 2013 Author: John Burkardt Parameters: Input, int N, the number of rows and columns of the matrix A. Input, double A[N*N], the N by N matrix. Output, int *FLAG, an error flag. 0, no error was detected. 1, the matrix was not positive definite. A NULL factor was returned. Output, double R8MAT_CHOLESKY_FACTOR_UPPER[N*N], the N by N upper triangular "Choresky" factor. */ { double *c; int i; int j; int k; double sum2; *flag = 0; c = r8mat_copy_new ( n, n, a ); for ( j = 0; j < n; j++ ) { for ( i = 0; i < j; i++ ) { c[j+i*n] = 0.0; } for ( i = j; i < n; i++ ) { sum2 = c[i+j*n]; for ( k = 0; k < j; k++ ) { sum2 = sum2 - c[k+j*n] * c[k+i*n]; } if ( i == j ) { if ( sum2 <= 0.0 ) { *flag = 1; return NULL; } c[j+i*n] = sqrt ( sum2 ); } else { if ( c[j+j*n] != 0.0 ) { c[j+i*n] = sum2 / c[j+j*n]; } else { c[j+i*n] = 0.0; } } } } return c; } /******************************************************************************/ double *r8mat_copy_new ( int m, int n, double a1[] ) /******************************************************************************/ /* Purpose: R8MAT_COPY_NEW copies one R8MAT to a "new" R8MAT. Discussion: An R8MAT is a doubly dimensioned array of R8 values, stored as a vector in column-major order. Licensing: This code is distributed under the MIT license. Modified: 26 July 2008 Author: John Burkardt Parameters: Input, int M, N, the number of rows and columns. Input, double A1[M*N], the matrix to be copied. Output, double R8MAT_COPY_NEW[M*N], the copy of A1. */ { double *a2; int i; int j; a2 = ( double * ) malloc ( m * n * sizeof ( double ) ); for ( j = 0; j < n; j++ ) { for ( i = 0; i < m; i++ ) { a2[i+j*m] = a1[i+j*m]; } } return a2; } /******************************************************************************/ double *r8mat_mmt_new ( int n1, int n2, int n3, double a[], double b[] ) /******************************************************************************/ /* Purpose: R8MAT_MMT_NEW computes C = A * B'. Discussion: An R8MAT is a doubly dimensioned array of R8 values, stored as a vector in column-major order. For this routine, the result is returned as the function value. Licensing: This code is distributed under the MIT license. Modified: 13 November 2012 Author: John Burkardt Parameters: Input, int N1, N2, N3, the order of the matrices. Input, double A[N1*N2], double B[N3*N2], the matrices to multiply. Output, double R8MAT_MMT_NEW[N1*N3], the product matrix C = A * B'. */ { double *c; int i; int j; int k; c = ( double * ) malloc ( n1 * n3 * sizeof ( double ) ); for ( i = 0; i < n1; i++ ) { for ( j = 0; j < n3; j++ ) { c[i+j*n1] = 0.0; for ( k = 0; k < n2; k++ ) { c[i+j*n1] = c[i+j*n1] + a[i+k*n1] * b[j+k*n3]; } } } return c; } /******************************************************************************/ void r8mat_print ( int m, int n, double a[], char *title ) /******************************************************************************/ /* Purpose: R8MAT_PRINT prints an R8MAT. Discussion: An R8MAT is a doubly dimensioned array of R8 values, stored as a vector in column-major order. Entry A(I,J) is stored as A[I+J*M] Licensing: This code is distributed under the MIT license. Modified: 28 May 2008 Author: John Burkardt Parameters: Input, int M, the number of rows in A. Input, int N, the number of columns in A. Input, double A[M*N], the M by N matrix. Input, char *TITLE, a title. */ { r8mat_print_some ( m, n, a, 1, 1, m, n, title ); return; } /******************************************************************************/ void r8mat_print_some ( int m, int n, double a[], int ilo, int jlo, int ihi, int jhi, char *title ) /******************************************************************************/ /* Purpose: R8MAT_PRINT_SOME prints some of an R8MAT. Discussion: An R8MAT is a doubly dimensioned array of R8 values, stored as a vector in column-major order. Licensing: This code is distributed under the MIT license. Modified: 26 June 2013 Author: John Burkardt Parameters: Input, int M, the number of rows of the matrix. M must be positive. Input, int N, the number of columns of the matrix. N must be positive. Input, double A[M*N], the matrix. Input, int ILO, JLO, IHI, JHI, designate the first row and column, and the last row and column to be printed. Input, char *TITLE, a title. */ { # define INCX 5 int i; int i2hi; int i2lo; int j; int j2hi; int j2lo; fprintf ( stdout, "\n" ); fprintf ( stdout, "%s\n", title ); if ( m <= 0 || n <= 0 ) { fprintf ( stdout, "\n" ); fprintf ( stdout, " (None)\n" ); return; } /* Print the columns of the matrix, in strips of 5. */ for ( j2lo = jlo; j2lo <= jhi; j2lo = j2lo + INCX ) { j2hi = j2lo + INCX - 1; if ( n < j2hi ) { j2hi = n; } if ( jhi < j2hi ) { j2hi = jhi; } fprintf ( stdout, "\n" ); /* For each column J in the current range... Write the header. */ fprintf ( stdout, " Col: "); for ( j = j2lo; j <= j2hi; j++ ) { fprintf ( stdout, " %7d ", j - 1 ); } fprintf ( stdout, "\n" ); fprintf ( stdout, " Row\n" ); fprintf ( stdout, "\n" ); /* Determine the range of the rows in this strip. */ if ( 1 < ilo ) { i2lo = ilo; } else { i2lo = 1; } if ( m < ihi ) { i2hi = m; } else { i2hi = ihi; } for ( i = i2lo; i <= i2hi; i++ ) { /* Print out (up to) 5 entries in row I, that lie in the current strip. */ fprintf ( stdout, "%5d:", i - 1 ); for ( j = j2lo; j <= j2hi; j++ ) { fprintf ( stdout, " %14g", a[i-1+(j-1)*m] ); } fprintf ( stdout, "\n" ); } } return; # undef INCX } /******************************************************************************/ double *r8mat_zeros_new ( int m, int n ) /******************************************************************************/ /* Purpose: R8MAT_ZEROS_NEW returns a new zeroed R8MAT. Discussion: An R8MAT is a doubly dimensioned array of R8 values, stored as a vector in column-major order. Licensing: This code is distributed under the MIT license. Modified: 26 September 2008 Author: John Burkardt Parameters: Input, int M, N, the number of rows and columns. Output, double R8MAT_ZEROS_NEW[M*N], the new zeroed matrix. */ { double *a; int i; int j; a = ( double * ) malloc ( m * n * sizeof ( double ) ); for ( j = 0; j < n; j++ ) { for ( i = 0; i < m; i++ ) { a[i+j*m] = 0.0; } } return a; } /******************************************************************************/ double *r8vec_uniform_01_new ( int n, int *seed ) /******************************************************************************/ /* Purpose: R8VEC_UNIFORM_01_NEW returns a unit pseudorandom R8VEC. Discussion: This routine implements the recursion seed = 16807 * seed mod ( 2^31 - 1 ) unif = seed / ( 2^31 - 1 ) The integer arithmetic never requires more than 32 bits, including a sign bit. Licensing: This code is distributed under the MIT license. Modified: 19 August 2004 Author: John Burkardt Reference: Paul Bratley, Bennett Fox, Linus Schrage, A Guide to Simulation, Second Edition, Springer, 1987, ISBN: 0387964673, LC: QA76.9.C65.B73. Bennett Fox, Algorithm 647: Implementation and Relative Efficiency of Quasirandom Sequence Generators, ACM Transactions on Mathematical Software, Volume 12, Number 4, December 1986, pages 362-376. Pierre L'Ecuyer, Random Number Generation, in Handbook of Simulation, edited by Jerry Banks, Wiley, 1998, ISBN: 0471134031, LC: T57.62.H37. Peter Lewis, Allen Goodman, James Miller, A Pseudo-Random Number Generator for the System/360, IBM Systems Journal, Volume 8, Number 2, 1969, pages 136-143. Parameters: Input, int N, the number of entries in the vector. Input/output, int *SEED, a seed for the random number generator. Output, double R8VEC_UNIFORM_01_NEW[N], the vector of pseudorandom values. */ { int i; const int i4_huge = 2147483647; int k; double *r; if ( *seed == 0 ) { fprintf ( stderr, "\n" ); fprintf ( stderr, "R8VEC_UNIFORM_01_NEW - Fatal error!\n" ); fprintf ( stderr, " Input value of SEED = 0.\n" ); exit ( 1 ); } r = ( double * ) malloc ( n * sizeof ( double ) ); for ( i = 0; i < n; i++ ) { k = *seed / 127773; *seed = 16807 * ( *seed - k * 127773 ) - k * 2836; if ( *seed < 0 ) { *seed = *seed + i4_huge; } r[i] = ( double ) ( *seed ) * 4.656612875E-10; } return r; } /******************************************************************************/ void timestamp ( ) /******************************************************************************/ /* Purpose: TIMESTAMP prints the current YMDHMS date as a time stamp. Example: 31 May 2001 09:45:54 AM Licensing: This code is distributed under the MIT license. Modified: 24 September 2003 Author: John Burkardt Parameters: None */ { # define TIME_SIZE 40 static char time_buffer[TIME_SIZE]; const struct tm *tm; time_t now; now = time ( NULL ); tm = localtime ( &now ); strftime ( time_buffer, TIME_SIZE, "%d %B %Y %I:%M:%S %p", tm ); fprintf ( stdout, "%s\n", time_buffer ); return; # undef TIME_SIZE }