/** * * @file testing_zcheck_aux.c * * @copyright 2019-2022 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, * Univ. Bordeaux. All rights reserved. * *** * * @brief Chameleon CHAMELEON_Complex64_t auxiliary testings routines * * @version 1.2.0 * @author Lucas Barros de Assis * @author Florent Pruvost * @author Mathieu Faverge * @author Nathalie Furmento * @author Alycia Lisito * @date 2022-03-30 * @precisions normal z -> c d s * */ #include "../control/common.h" #include <stdlib.h> #include <stdio.h> #include <string.h> #include <math.h> #include <chameleon.h> #if !defined(CHAMELEON_SIMULATION) #include <coreblas/cblas.h> #include <coreblas/lapacke.h> #include <coreblas.h> #if defined(CHAMELEON_USE_MPI) #include <mpi.h> #endif #include "testings.h" #include "testing_zcheck.h" #include <chameleon/flops.h> #ifndef max #define max( _a_, _b_ ) ( (_a_) > (_b_) ? (_a_) : (_b_) ) #endif /** ******************************************************************************** * * @ingroup testing * * @brief Compares two matrices by their norms. * ******************************************************************************* * * @param[in] uplo * Whether it is a upper triangular matrix, a lower triangular matrix or a general matrix. * * @param[in] M * The number of rows of the matrices A and B. * * @param[in] N * The number of columns of the matrices A and B. * * @param[in] A * The matrix A. * * @param[in] LDA * The leading dimension of the matrix A. * * @param[in] B * The matrix B. * * @param[in] LDB * The leading dimension of the matrix B. * * @retval 0 successfull comparison * ******************************************************************************* */ int check_zmatrices_std( run_arg_list_t *args, cham_uplo_t uplo, int M, int N, CHAMELEON_Complex64_t *A, int LDA, CHAMELEON_Complex64_t *B, int LDB ) { int info_solution = 0; double Anorm, Rnorm, result; double eps = LAPACKE_dlamch_work('e'); double *work = (double *)malloc( LDA*N*sizeof(double) ); /* Computes the norms */ if ( uplo == ChamUpperLower ) { Anorm = LAPACKE_zlange_work( LAPACK_COL_MAJOR, 'M', M, N, A, LDA, work ); } else { Anorm = LAPACKE_zlantr_work( LAPACK_COL_MAJOR, 'M', chameleon_lapack_const(uplo), 'N', M, N, A, LDA, work ); } /* Computes the difference with the core function */ CORE_zgeadd( ChamNoTrans, M, N, 1, A, LDA, -1, B, LDB ); /* Computes the residual's norm */ if ( uplo == ChamUpperLower ) { Rnorm = LAPACKE_zlange_work( LAPACK_COL_MAJOR, 'M', M, N, B, LDB, work ); } else { Rnorm = LAPACKE_zlantr_work( LAPACK_COL_MAJOR, 'M', chameleon_lapack_const(uplo), 'N', M, N, B, LDB, work ); } if ( Anorm != 0. ) { result = Rnorm / (Anorm * eps); } else { result = Rnorm; } /* Verifies if the result is inside a threshold */ if ( isnan(Rnorm) || isinf(Rnorm) || isnan(result) || isinf(result) || (result > 10.0) ) { info_solution = 1; } else { info_solution = 0; } run_arg_add_double( args, "||A||", Anorm ); run_arg_add_double( args, "||B||", Rnorm ); free(work); (void)args; return info_solution; } /** ******************************************************************************** * * @ingroup testing * * @brief Compares two matrices by their norms. * ******************************************************************************* * * @param[in] uplo * Whether it is a upper triangular matrix, a lower triangular matrix or a general matrix. * * @param[in] descA * The descriptor of the matrix A. * * @param[in] descB * The descriptor of the matrix B. * * @retval 0 successfull comparison * ******************************************************************************* */ int check_zmatrices( run_arg_list_t *args, cham_uplo_t uplo, CHAM_desc_t *descA, CHAM_desc_t *descB ) { int info_solution = 0; int M = descA->m; int N = descB->n; int LDA = M; int LDB = M; int rank = CHAMELEON_Comm_rank(); CHAMELEON_Complex64_t *A = NULL; CHAMELEON_Complex64_t *B = NULL; if ( rank == 0 ) { A = (CHAMELEON_Complex64_t *)malloc((size_t)(LDA) * (size_t)(N) * sizeof(CHAMELEON_Complex64_t)); B = (CHAMELEON_Complex64_t *)malloc((size_t)(LDB) * (size_t)(N) * sizeof(CHAMELEON_Complex64_t)); if ( (A == NULL) || (B == NULL) ) { free( A ); free( B ); return CHAMELEON_ERR_OUT_OF_RESOURCES; } } /* Converts the matrices to LAPACK layout in order to compare them on the main process */ CHAMELEON_zDesc2Lap( uplo, descA, A, LDA ); CHAMELEON_zDesc2Lap( uplo, descB, B, LDB ); if ( rank == 0 ) { info_solution = check_zmatrices_std( args, uplo, M, N, A, LDA, B, LDB ); free( A ); free( B ); } /* Broadcasts the result from the main processus */ #if defined(CHAMELEON_USE_MPI) MPI_Bcast( &info_solution, 1, MPI_INT, 0, MPI_COMM_WORLD ); #endif return info_solution; } /** ******************************************************************************** * * @ingroup testing * * @brief Compares two core function computed norms. * ******************************************************************************* * * @param[in] matrix_type * Whether it is a general, triangular, hermitian or symmetric matrix. * * @param[in] norm_type * Whether the norm is a Max, One, Inf or Frobenius norm. * * @param[in] uplo * Whether it is a upper triangular matrix, a lower triangular matrix or a general matrix. * * @param[in] diag * Whether it is a unitary diagonal matrix or not. * * @param[in] norm_cham * The computed norm. * * @param[in] M * The number of rows of the matrix A. * * @param[in] N * The number of columns of the matrix A. * * @param[in] A * The matrix A. * * @param[in] LDA * The leading dimension of the matrix A. * * @retval 0 successfull comparison * ******************************************************************************* */ int check_znorm_std( run_arg_list_t *args, cham_mtxtype_t matrix_type, cham_normtype_t norm_type, cham_uplo_t uplo, cham_diag_t diag, double norm_cham, int M, int N, CHAMELEON_Complex64_t *A, int LDA ) { int info_solution = 0; double *work = (double*) malloc(chameleon_max(M, N)*sizeof(double)); double norm_lapack; double result; double eps = LAPACKE_dlamch_work('e'); /* Computes the norm with the LAPACK function */ switch (matrix_type) { case ChamGeneral: norm_lapack = LAPACKE_zlange_work( LAPACK_COL_MAJOR, chameleon_lapack_const(norm_type), M, N, A, LDA, work ); break; #if defined(PRECISION_z) || defined(PRECISION_c) case ChamHermitian: norm_lapack = LAPACKE_zlanhe_work( LAPACK_COL_MAJOR, chameleon_lapack_const(norm_type), chameleon_lapack_const(uplo), M, A, LDA, work ); break; #endif case ChamSymmetric: norm_lapack = LAPACKE_zlansy_work( LAPACK_COL_MAJOR, chameleon_lapack_const(norm_type), chameleon_lapack_const(uplo), M, A, LDA, work ); break; case ChamTriangular: norm_lapack = LAPACKE_zlantr_work( LAPACK_COL_MAJOR, chameleon_lapack_const(norm_type), chameleon_lapack_const(uplo), chameleon_lapack_const(diag), M, N, A, LDA, work ); break; default: fprintf(stderr, "check_znorm: matrix_type(%d) unsupported\n", matrix_type ); free( work ); return 1; } /* Compares the norms */ result = fabs( norm_cham - norm_lapack ) / ( norm_lapack * eps ); run_arg_add_double( args, "||A||", norm_cham ); run_arg_add_double( args, "||B||", norm_lapack ); switch(norm_type) { case ChamInfNorm: /* Sum order on the line can differ */ result = result / (double)N; break; case ChamOneNorm: /* Sum order on the column can differ */ result = result / (double)M; break; case ChamFrobeniusNorm: /* Sum order on every element can differ */ result = result / ((double)M * (double)N); break; case ChamMaxNorm: default: #if defined(PRECISION_z) || defined(PRECISION_c) /* Add a factor two to macth different implementation of cabs */ result = result / 2; #else /* result should be perfectly equal */ #endif ; } run_arg_add_double( args, "||R||", result ); info_solution = ( result < 1 ) ? 0 : 1; free(work); return info_solution; } /** ******************************************************************************** * * @ingroup testing * * @brief Compares the Chameleon computed norm with a core function computed one. * ******************************************************************************* * * @param[in] matrix_type * Whether it is a general, triangular, hermitian or symmetric matrix. * * @param[in] norm_type * Whether the norm is a Max, One, Inf or Frobenius norm. * * @param[in] uplo * Whether it is a upper triangular matrix, a lower triangular matrix or a general matrix. * * @param[in] diag * Whether it is a unitary diagonal matrix or not. * * @param[in] norm_cham * The Chameleon computed norm. * * @param[in] descA * The descriptor of the matrix A. * * @retval 0 successfull comparison * ******************************************************************************* */ int check_znorm( run_arg_list_t *args, cham_mtxtype_t matrix_type, cham_normtype_t norm_type, cham_uplo_t uplo, cham_diag_t diag, double norm_cham, CHAM_desc_t *descA ) { int info_solution = 0; int M = descA->m; int N = descA->n; int rank = CHAMELEON_Comm_rank(); CHAMELEON_Complex64_t *A = NULL; int LDA = M; if ( rank == 0 ) { A = (CHAMELEON_Complex64_t *)malloc(LDA*N*sizeof(CHAMELEON_Complex64_t)); } /* Converts the matrix to LAPACK layout in order to use the LAPACK norm function */ CHAMELEON_zDesc2Lap( uplo, descA, A, LDA ); if ( rank == 0 ) { info_solution = check_znorm_std( args, matrix_type, norm_type, uplo, diag, norm_cham, M, N, A, LDA ); } /* Broadcasts the result from the main processus */ #if defined(CHAMELEON_USE_MPI) MPI_Bcast( &info_solution, 1, MPI_INT, 0, MPI_COMM_WORLD ); #endif return info_solution; } /** ******************************************************************************** * * @ingroup testing * * @brief Compares two core function computed sum. * ******************************************************************************* * * @param[in] uplo * Whether it is a upper triangular matrix, a lower triangular matrix or a general matrix. * * @param[in] trans * Whether the first matrix is transposed, conjugate transposed or not transposed. * * @param[in] M * The number of rows of the matrices A and C. * * @param[in] N * The number of columns of the matrices B and C. * * @param[in] alpha * The scalar alpha. * * @param[in] A * The matrix A. * * @param[in] LDA * The leading dimension of the matrix A. * * @param[in] beta * The scalar beta. * * @param[in] Bref * The matrix Bref. * * @param[in] Bcham * The matrix of the computed result A+B. * * @retval 0 successfull comparison * ******************************************************************************* */ int check_zsum_std( run_arg_list_t *args, cham_uplo_t uplo, cham_trans_t trans, int M, int N, CHAMELEON_Complex64_t alpha, CHAMELEON_Complex64_t *A, int LDA, CHAMELEON_Complex64_t beta, CHAMELEON_Complex64_t *Bref, CHAMELEON_Complex64_t *Bcham, int LDB ) { int info_solution = 0; int Am = (trans == ChamNoTrans)? M : N; int An = (trans == ChamNoTrans)? N : M; double Anorm, Binitnorm, Rnorm, result; CHAMELEON_Complex64_t mzone = -1.0; cham_uplo_t uploA = uplo; /* Computes the max norms of A, B and A+B */ if ( uplo == ChamUpperLower ) { Anorm = LAPACKE_zlange( LAPACK_COL_MAJOR, 'M', Am, An, A, LDA ); Binitnorm = LAPACKE_zlange( LAPACK_COL_MAJOR, 'M', M, N, Bref, LDB ); } else { if ( trans == ChamNoTrans ) { Anorm = LAPACKE_zlantr( LAPACK_COL_MAJOR, 'M', chameleon_lapack_const(uplo), 'N', Am, An, A, LDA ); } else { uploA = (uplo == ChamUpper) ? ChamLower : ChamUpper; Anorm = LAPACKE_zlantr( LAPACK_COL_MAJOR, 'M', chameleon_lapack_const(uploA), 'N', Am, An, A, LDA ); } Binitnorm = LAPACKE_zlantr( LAPACK_COL_MAJOR, 'M', chameleon_lapack_const(uplo), 'N', M, N, Bref, LDB ); } double eps = LAPACKE_dlamch_work('e'); double *work = malloc(chameleon_max(M, N)* sizeof(double)); /* Makes the sum with the core function */ if ( uplo == ChamUpperLower ) { CORE_zgeadd( trans, M, N, alpha, A, LDA, beta, Bref, LDB ); } else { CORE_ztradd( uplo, trans, M, N, alpha, A, LDA, beta, Bref, LDB ); } cblas_zaxpy( LDB*N, CBLAS_SADDR(mzone), Bcham, 1, Bref, 1 ); /* Calculates the norm from the core function's result */ if ( uplo == ChamUpperLower ) { Rnorm = LAPACKE_zlange_work( LAPACK_COL_MAJOR, 'M', M, N, Bref, LDB, work ); } else { Rnorm = LAPACKE_zlantr_work( LAPACK_COL_MAJOR, 'M', chameleon_lapack_const(uplo), 'N', M, N, Bref, LDB, work ); } result = Rnorm / (max(Anorm, Binitnorm) * eps); run_arg_add_double( args, "||A||", Anorm ); run_arg_add_double( args, "||B||", Binitnorm ); run_arg_add_double( args, "||R||", Rnorm ); /* Verifies if the result is inside a threshold */ if ( isnan(Rnorm) || isinf(Rnorm) || isnan(result) || isinf(result) || (result > 10.0) ) { info_solution = 1; } else { info_solution = 0; } free(work); (void)args; return info_solution; } /** ******************************************************************************** * * @ingroup testing * * @brief Compares a Chameleon computed sum with a core function computed one. * ******************************************************************************* * * @param[in] uplo * Whether it is a upper triangular matrix, a lower triangular matrix or a general matrix. * * @param[in] trans * Whether the first matrix is transposed, conjugate transposed or not transposed. * * @param[in] alpha * The scalar alpha. * * @param[in] descA * The descriptor of the matrix A. * * @param[in] beta * The scalar beta. * * @param[in] descBref * The descriptor of the matrix Bref. * * @param[in] descBcham * The descriptor of the matrix of the Chameleon computed result A+B. * * @retval 0 successfull comparison * ******************************************************************************* */ int check_zsum ( run_arg_list_t *args, cham_uplo_t uplo, cham_trans_t trans, CHAMELEON_Complex64_t alpha, CHAM_desc_t *descA, CHAMELEON_Complex64_t beta, CHAM_desc_t *descBref, CHAM_desc_t *descBcham ) { int info_solution = 0; int M = descBref->m; int N = descBref->n; int Am = (trans == ChamNoTrans)? M : N; int An = (trans == ChamNoTrans)? N : M; int LDA = Am; int LDB = M; int rank = CHAMELEON_Comm_rank(); CHAMELEON_Complex64_t *A = NULL; CHAMELEON_Complex64_t *Bref = NULL; CHAMELEON_Complex64_t *Bcham = NULL; cham_uplo_t uploA = uplo; if ( rank == 0 ) { A = malloc( LDA*An*sizeof(CHAMELEON_Complex64_t) ); Bref = malloc( LDB*N* sizeof(CHAMELEON_Complex64_t) ); Bcham = malloc( LDB*N* sizeof(CHAMELEON_Complex64_t) ); } if ( uplo != ChamUpperLower && trans != ChamNoTrans ) { uploA = (uplo == ChamUpper) ? ChamLower : ChamUpper; } /* Creates the LAPACK version of the matrices */ CHAMELEON_zDesc2Lap( uploA, descA, A, LDA ); CHAMELEON_zDesc2Lap( uplo, descBref, Bref, LDB ); CHAMELEON_zDesc2Lap( uplo, descBcham, Bcham, LDB ); if ( rank == 0 ) { info_solution = check_zsum_std( args, uplo, trans, M, N, alpha, A, LDA, beta, Bref, Bcham, LDB ); free(A); free(Bref); free(Bcham); } /* Broadcasts the result from the main processus */ #if defined(CHAMELEON_USE_MPI) MPI_Bcast( &info_solution, 1, MPI_INT, 0, MPI_COMM_WORLD ); #endif (void)args; return info_solution; } /** ******************************************************************************** * * @ingroup testing * * @brief Compares two core functions computed scale. * ******************************************************************************* * * @param[in] uplo * Whether it is a upper triangular matrix, a lower triangular matrix or a general matrix. * * @param[in] M * The number of rows of the matrices A and Ainit. * * @param[in] N * The number of columns of the matrices A and Ainit. * * @param[in] alpha * The scalar alpha. * * @param[in] Ainit * The matrix Ainit. * * @param[in] A * The scaled matrix A. * * @param[in] LDA * The leading dimension of the matrices A and Ainit. * * @retval 0 successfull comparison * ******************************************************************************* */ int check_zscale_std( run_arg_list_t *args, cham_uplo_t uplo, int M, int N, CHAMELEON_Complex64_t alpha, CHAMELEON_Complex64_t *Ainit, CHAMELEON_Complex64_t *A, int LDA ) { int info_solution; /* Scales using core function */ CORE_zlascal( uplo, M, N, alpha, Ainit, LDA ); /* Compares the two matrices */ info_solution = check_zmatrices_std( args, uplo, M, N, Ainit, LDA, A, LDA ); return info_solution; } /** ******************************************************************************** * * @ingroup testing * * @brief Compares a Chameleon computed scale with a core function computed one. * ******************************************************************************* * * @param[in] uplo * Whether it is a upper triangular matrix, a lower triangular matrix or a general matrix. * * @param[in] alpha * The scalar alpha. * * @param[in] descAinit * The descriptor of the matrix Ainit. * * @param[in] descA * The descriptor of the scaled matrix A. * * @retval 0 successfull comparison * ******************************************************************************* */ int check_zscale( run_arg_list_t *args, cham_uplo_t uplo, CHAMELEON_Complex64_t alpha, CHAM_desc_t *descAinit, CHAM_desc_t *descA ) { int info_solution; int M = descA->m; int N = descA->n; int LDA = M; int rank = CHAMELEON_Comm_rank(); CHAMELEON_Complex64_t *A = NULL; CHAMELEON_Complex64_t *Ainit = NULL; if ( rank == 0 ) { A = (CHAMELEON_Complex64_t *)malloc(LDA*N*sizeof(CHAMELEON_Complex64_t)); Ainit = (CHAMELEON_Complex64_t *)malloc(LDA*N*sizeof(CHAMELEON_Complex64_t)); } /* Converts the matrix to LAPACK layout in order to scale with BLAS */ CHAMELEON_zDesc2Lap( uplo, descA, A, LDA ); CHAMELEON_zDesc2Lap( uplo, descAinit, Ainit, LDA ); /* Compares the two matrices */ if ( rank == 0 ) { info_solution = check_zscale_std( args, uplo, M, N, alpha, Ainit, A, LDA ); } /* Broadcasts the result from the main processus */ #if defined(CHAMELEON_USE_MPI) MPI_Bcast( &info_solution, 1, MPI_INT, 0, MPI_COMM_WORLD ); #endif if ( rank == 0 ) { free( A ); free( Ainit ); } return info_solution; } /** ******************************************************************************** * * @ingroup testing * * @brief Checks if the rank of the matrix A is K. * ******************************************************************************* * * @param[in] M * The number of rows of the matrix A. * * @param[in] N * The number of columns of the matrix A. * * @param[in] K * The rank of the matrix A. * * @param[in] A * The matrix A. * * @param[in] LDA * The leading dimension of the matrix A. * * @retval 0 success, else failure * ******************************************************************************* */ int check_zrankk_std( run_arg_list_t *args, int M, int N, int K, CHAMELEON_Complex64_t *A, int LDA ) { int info_solution = 0; int minMN = chameleon_min(M, N); double Anorm, Rnorm, result; double eps = LAPACKE_dlamch_work('e'); Anorm = LAPACKE_zlange( LAPACK_COL_MAJOR, 'F', M, N, A, LDA ); /* check rank of A using SVD, value K+1 of Sigma must be small enough */ CHAMELEON_Complex64_t *U = malloc( M * M * sizeof(CHAMELEON_Complex64_t) ); CHAMELEON_Complex64_t *VT = malloc( N * N * sizeof(CHAMELEON_Complex64_t) ); double *S = malloc( minMN * sizeof(double) ); double *work = malloc( minMN * sizeof(double) ); LAPACKE_zgesvd( LAPACK_COL_MAJOR, 'A', 'A', M, N, A, LDA, S, U, M, VT, N, work ); /* Computes the residual's norm */ if ( K >= minMN ) { Rnorm = 0.; } else { Rnorm = S[K]; } run_arg_add_double( args, "||A||", Anorm ); run_arg_add_double( args, "||R||", Rnorm ); result = Rnorm / (Anorm * eps); /* Verifies if the result is inside a threshold */ if ( isnan(Rnorm) || isinf(Rnorm) || isnan(result) || isinf(result) || (result > 10.0) ) { info_solution = 1; } else { info_solution = 0; } free(S); free(U); free(VT); free(work); return info_solution; } /** ******************************************************************************** * * @ingroup testing * * @brief Checks if the rank of the matrix A is K. * ******************************************************************************* * * @param[in] K * The rank of the matrix A. * * @param[in] descA * The descriptor of the matrix A. * * @retval 0 success, else failure * ******************************************************************************* */ int check_zrankk( run_arg_list_t *args, int K, CHAM_desc_t *descA ) { int info_solution = 0; int M = descA->m; int N = descA->n; int LDA = descA->m; int rank = CHAMELEON_Comm_rank(); /* Converts the matrices to LAPACK layout in order to check values on the main process */ CHAMELEON_Complex64_t *A = NULL; if ( rank == 0 ) { A = malloc( M*N*sizeof(CHAMELEON_Complex64_t) ); } CHAMELEON_Desc2Lap( ChamUpperLower, descA, A, LDA ); /* check rank of A using SVD, value K+1 of Sigma must be small enough */ if ( rank == 0 ) { info_solution = check_zrankk_std( args, M, N, K, A, LDA ); free( A ); } /* Broadcasts the result from the main processus */ #if defined(CHAMELEON_USE_MPI) MPI_Bcast( &info_solution, 1, MPI_INT, 0, MPI_COMM_WORLD ); #endif return info_solution; } #endif /* defined(CHAMELEON_SIMULATION) */