Mentions légales du service

Skip to content
Snippets Groups Projects
testing_zcheck_svd.c 8.12 KiB
/**
 *
 * @file testing_zcheck_svd.c
 *
 * @copyright 2019-2023 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 Alycia Lisito
 * @date 2023-01-05
 * @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)

#if defined(CHAMELEON_USE_MPI)
#include <mpi.h>
#endif
#include "testings.h"
#include "testing_zcheck.h"
#include <chameleon/flops.h>

/**
 ********************************************************************************
 *
 * @ingroup testing
 *
 * @brief Checks if the Chameleon SVD algorithm works: Ainit = U * mat( S ) * Vt.
 *        - U and Vt should be orthogonal.
 *        - Sinit and S should be the same.
 *        - Ainit = U * mat( S ) * Vt.
 *
 *******************************************************************************
 *
 * @param[in] jobu
 *          Specifies options for computing all or part of the matrix U.
 *
 * @param[in] jobvt
 *          Specifies options for computing all or part of the matrix V^H.
 *
 * @param[in] M
 *          The number of rows of the matrices Ainit, A and U.
 *
 * @param[in] N
 *          The number of columns of the matrices Ainit, A and Vt.
 *
 * @param[in] Ainit
 *          The matrix Ainit (initial matrix A).
 *
 * @param[in] A
 *          The matrix A after the SVD, can contain parts of the matrix U or Vt
 *          or nothing (depending on the values of jobu and jobvt).
 *
 * @param[in] LDA
 *          The leading dimension of the matrices A and Ainit.
 *
 * @param[in] Sinit
 *          The vector with the singular values of the matrix Ainit
 *          (contains the K = min(M, N) singular values of Ainit).
 *
 * @param[in] S
 *          The vector with the singular values of the matrix Ainit
 *          computed by the Chameleon SVD algorithm.
 *
 * @param[in] U
 *          The orthogonal matrix U computed by the Chameleon SVD algorithm can
 *          contain all of U, a part of U or nothing (NULL) depending on the value of jobu;
 *          if jobu == AllVec : dimension: M * M
 *          if jobu == SVec :   dimension: M * min(M, N)
 *          if jobu == NoVec or OVec : U = NULL
 *
 * @param[in] LDU
 *          The leading dimension of the matrix U.
 *
 * @param[in] Vt
 *          The orthogonal matrix Vt computed by the Chameleon SVD algorithm can
 *          contain all of Vt, a part of Vt or nothing (NULL) depending on the value of jobvt;
 *          if jobuvt == AllVec : dimension: N * N
 *          if jobvt == SVec :    dimension: min(M, N) * N
 *          if jobvt == NoVec or OVec : Vt = NULL
 *
 * @param[in] LDVt
 *          The leading dimension of the matrix Vt.
 *
 * @retval 0 successfull comparison
 *
 *******************************************************************************
 */
int check_zgesvd_std( run_arg_list_t *args, cham_job_t jobu, cham_job_t jobvt, int M, int N, CHAMELEON_Complex64_t *Ainit, CHAMELEON_Complex64_t *A, int LDA,
                     double *Sinit, double *S, CHAMELEON_Complex64_t *U, int LDU, CHAMELEON_Complex64_t *Vt, int LDVt )
{
    int info_solution = 0;
    double result;
    int k;
    int K = chameleon_min(M, N);
    cham_fixdbl_t eps = testing_getaccuracy();

    /* Checks if U is orthogonal */
    switch ( jobu ) {
    case ChamAllVec:
        info_solution += check_zortho_std( args, M, M, U, LDU );
        break;
    case ChamSVec:
        info_solution += check_zortho_std( args, M, K, U, LDU );
        break;
    case ChamOVec:
        info_solution += check_zortho_std( args, M, K, A, LDA );
        break;
    default:
       ;
    }

    /* Checks if Vt is orthogonal */
    switch ( jobvt ) {
    case ChamAllVec:
        info_solution += check_zortho_std( args, N, N, Vt, LDVt );
        break;
    case ChamSVec:
        info_solution += check_zortho_std( args, K, N, Vt, LDVt );
        break;
    case ChamOVec:
        info_solution += check_zortho_std( args, K, N, A, LDA );
        break;
    default:
       ;
    }

    /* checks if Sinit and S are the same */
    double maxSV     = chameleon_max( fabs(Sinit[0]), fabs(S[0]) );
    double maxSVdiff = fabs( fabs(Sinit[0]) - fabs(S[0]) );
    double maxtmp, maxdifftmp;

    for ( k = 1; k < K; k++ ) {
        maxdifftmp = fabs( fabs(Sinit[k]) - fabs(S[k]) );
        maxtmp     = chameleon_max( fabs(Sinit[k]), fabs(S[k]) );

        /* Update */
        maxSV     = chameleon_max( maxtmp, maxSV );
        maxSVdiff = chameleon_max( maxdifftmp, maxSVdiff );
    }

    result = maxSVdiff / ( K * eps * maxSV );

    if ( isnan(result) || isinf(result) || (result > 60.0) ) {
        info_solution += 1;
    }

    if ( (jobu == ChamAllVec) && (jobvt == ChamAllVec) ) {
        /* To do: create mat( S ) */
    }
    result = info_solution;

    run_arg_add_double( args, "||R||", result );

    (void)Ainit;
    return info_solution;
}

/**
 ********************************************************************************
 *
 * @ingroup testing
 *
 * @brief Checks if the Chameleon SVD algorithm works: descAinit = U * mat( S ) * Vt.
 *        - U and Vt should be orthogonal.
 *        - Sinit and S should be the same.
 *        - descAinit = U * mat( S ) * Vt.
 *
 *******************************************************************************
 *
 * @param[in] jobu
 *          Specifies options for computing all or part of the matrix U.
 *
 * @param[in] jobvt
 *          Specifies options for computing all or part of the matrix V^H.
 *
 * @param[in] descAinit
 *          The descriptor of the matrix Ainit (initial matrix A).
 *
 * @param[in] descA
 *          The descriptor of the matrix A after the SVD, can contain parts of the matrix
 *          U or Vt or nothing (depending on the values of jobu and jobvt).
 *
 * @param[in] Sinit
 *          The vector with the singular values of the matrix Ainit
 *          (contains the K = min(M, N) singular values of Ainit).
 *
 * @param[in] S
 *          The vector with the singular values of the matrix Ainit
 *          computed by the Chameleon SVD algorithm.
 *
 * @param[in] U
 *          The orthogonal matrix U computed by the Chameleon SVD algorithm can
 *          contain all of U, a part of U or nothing (NULL) depending on the value of jobu;
 *          if jobu == AllVec : dimension: M * M
 *          if jobu == SVec :   dimension: M * min(M, N)
 *          if jobu == NoVec or OVec : U = NULL
 *
 * @param[in] LDU
 *          The leading dimension of the matrix U.
 *
 * @param[in] Vt
 *          The orthogonal matrix Vt computed by the Chameleon SVD algorithm can
 *          contain all of Vt, a part of Vt or nothing (NULL) depending on the value of jobvt;
 *          if jobuvt == AllVec : dimension: N * N
 *          if jobvt == SVec :    dimension: min(M, N) * N
 *          if jobvt == NoVec or OVec : Vt = NULL
 *
 * @param[in] LDVt
 *          The leading dimension of the matrix Vt.
 *
 * @retval 0 successfull comparison
 *
 *******************************************************************************
 */
int check_zgesvd( run_arg_list_t *args, cham_job_t jobu, cham_job_t jobvt, CHAM_desc_t *descAinit, CHAM_desc_t *descA,
                  double *Sinit, double *S, CHAMELEON_Complex64_t *U, int LDU, CHAMELEON_Complex64_t *Vt, int LDVt )
{
    int info_solution;
    int rank = CHAMELEON_Comm_rank();
    CHAMELEON_Complex64_t *Ainit, *A;
    int M    = descA->m;
    int N    = descA->n;
    int LDA  = descA->lm;

    if ( rank == 0 ) {
        Ainit = malloc( LDA*N*sizeof(CHAMELEON_Complex64_t) );
        A     = malloc( LDA*N*sizeof(CHAMELEON_Complex64_t) );
    }

    CHAMELEON_zDesc2Lap( ChamUpperLower, descAinit, Ainit, LDA );
    CHAMELEON_zDesc2Lap( ChamUpperLower, descA,     A,     LDA );

    if ( rank == 0 ) {

        info_solution = check_zgesvd_std( args, jobu, jobvt, M, N, Ainit, A, LDA, Sinit, S, U, LDU, Vt, LDVt  );

        free( Ainit );
        free( A     );
    }

#if defined(CHAMELEON_USE_MPI)
    MPI_Bcast( &info_solution, 1, MPI_INT, 0, MPI_COMM_WORLD );
#endif

    return info_solution;
}

#endif /* defined(CHAMELEON_SIMULATION) */