/*
 *  -- MAGMA (version 1.1) --
 *     Univ. of Tennessee, Knoxville
 *     Univ. of California, Berkeley
 *     Univ. of Colorado, Denver
 *     April 2012
 *
 * @generated c Fri Nov 22 14:21:34 2013
 *
 **/
// includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

// includes, project
#include "flops.h"
#include "magma.h"
#include "magma_lapack.h"
#include "testings.h"

/* ////////////////////////////////////////////////////////////////////////////
   -- Testing cgetri_mic
*/
int main( int argc, char** argv)
{
    /* Initialize */
    magma_queue_t  queue;
    magma_device_t device;
    magma_int_t num = 0;
    magma_err_t err;

    magma_init();
    err = magma_get_devices( &device, 1, &num );
    if ( err != MAGMA_SUCCESS or num < 1 ) {
	    fprintf( stderr, "magma_get_devices failed: %d\n", err );
	    exit(-1);
    }
    err = magma_queue_create( device, &queue );
    if ( err != MAGMA_SUCCESS ) {
	    fprintf( stderr, "magma_queue_create failed: %d\n", err );
	    exit(-1);
    }

    real_Double_t   gflops, mic_perf, mic_time, cpu_perf, cpu_time;
    magmaFloatComplex *h_A, *h_R, *work;
    magmaFloatComplex *d_A, *dwork;
    magmaFloatComplex c_neg_one = MAGMA_C_NEG_ONE;
    magma_int_t N, n2, lda, ldda, info, lwork, ldwork;
    magma_int_t ione     = 1;
    magma_int_t ISEED[4] = {0,0,0,1};
    magmaFloatComplex tmp;
    float error, rwork[1];
    magma_int_t *ipiv;
    magma_int_t status = 0;
    
    magma_opts opts;
    parse_opts( argc, argv, &opts );
    opts.lapack |= opts.check;  // check (-c) implies lapack (-l)
    
    float tol = 30 * opts.tolerance * lapackf77_slamch("E");
    
    printf("    N   CPU GFlop/s (sec)   MIC GFlop/s (sec)   ||R||_F / ||A||_F\n");
    printf("=================================================================\n");
    for( int i = 0; i < opts.ntest; ++i ) {
        for( int iter = 0; iter < opts.niter; ++iter ) {
            N = opts.nsize[i];
            lda    = N;
            n2     = lda*N;
            ldda   = ((N+31)/32)*32;
            ldwork = N * magma_get_cgetri_nb( N );
            gflops = FLOPS_CGETRI( N ) / 1e9;
            
            /* query for lapack workspace size */
            lwork = -1;
            lapackf77_cgetri( &N, h_A, &lda, ipiv, &tmp, &lwork, &info );
            if (info != 0)
                printf("lapackf77_cgetri returned error %d: %s.\n",
                       (int) info, magma_strerror( info ));
            lwork = int( MAGMA_C_REAL( tmp ));
            
            TESTING_MALLOC_HOST(    ipiv,  magma_int_t,     N      );
            TESTING_MALLOC_HOST(    work,  magmaFloatComplex, lwork  );
            TESTING_MALLOC_HOST(    h_A,   magmaFloatComplex, n2     );
            TESTING_MALLOC_HOST( h_R,   magmaFloatComplex, n2     );
            TESTING_MALLOC_DEV(  d_A,   magmaFloatComplex, ldda*N );
            TESTING_MALLOC_DEV(  dwork, magmaFloatComplex, ldwork );
            
            /* Initialize the matrix */
            lapackf77_clarnv( &ione, ISEED, &n2, h_A );
            error = lapackf77_clange( "f", &N, &N, h_A, &lda, rwork );  // norm(A)
            
            /* Factor the matrix. Both MAGMA and LAPACK will use this factor. */
            magma_csetmatrix( N, N, h_A, 0, lda, d_A, 0, ldda, queue );
            magma_cgetrf_mic( N, N, d_A, 0, ldda, ipiv, &info, queue );
            magma_cgetmatrix( N, N, d_A, 0, ldda, h_A, 0, lda, queue );
            
            // check for exact singularity
            //h_A[ 10 + 10*lda ] = MAGMA_C_MAKE( 0.0, 0.0 );
            //magma_csetmatrix( N, N, h_A, lda, d_A, ldda );
            
            /* ====================================================================
               Performs operation using MAGMA
               =================================================================== */
            mic_time = magma_wtime();
            magma_cgetri_mic( N,    d_A, ldda, ipiv, dwork, ldwork, &info, queue );
            mic_time = magma_wtime() - mic_time;
            mic_perf = gflops / mic_time;
            if (info != 0)
                printf("magma_cgetri_mic returned error %d: %s.\n",
                       (int) info, magma_strerror( info ));
            
            magma_cgetmatrix( N, N, d_A, 0, ldda, h_R, 0, lda, queue );
            
            /* =====================================================================
               Performs operation using LAPACK
               =================================================================== */
            if ( opts.lapack ) {
                cpu_time = magma_wtime();
                lapackf77_cgetri( &N,     h_A, &lda, ipiv, work, &lwork, &info );
                cpu_time = magma_wtime() - cpu_time;
                cpu_perf = gflops / cpu_time;
                if (info != 0)
                    printf("lapackf77_cgetri returned error %d: %s.\n",
                           (int) info, magma_strerror( info ));
                
                /* =====================================================================
                   Check the result compared to LAPACK
                   =================================================================== */
                blasf77_caxpy( &n2, &c_neg_one, h_A, &ione, h_R, &ione );
                error = lapackf77_clange( "f", &N, &N, h_R, &lda, rwork ) / error;
                
                printf( "%5d   %7.2f (%7.2f)   %7.2f (%7.2f)   %8.2e%s\n",
                        (int) N, cpu_perf, cpu_time, mic_perf, mic_time,
                        error, (error < tol ? "" : "  failed"));
                status |= ! (error < tol);
            }
            else {
                printf( "%5d     ---   (  ---  )   %7.2f (%7.2f)     ---\n",
                        (int) N, mic_perf, mic_time );
            }
            
            TESTING_FREE_HOST(     ipiv  );
            TESTING_FREE_HOST(     work  );
            TESTING_FREE_HOST(     h_A   );
            TESTING_FREE_HOST( h_R   );
            TESTING_FREE_DEV(  d_A   );
            TESTING_FREE_DEV(  dwork );
        }
        if ( opts.niter > 1 ) {
            printf( "\n" );
        }
    }

    /* Shutdown */
    magma_queue_destroy( queue );
    magma_finalize();
    return status;
}
