/*
    -- 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:35 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 cgeqrf
*/
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;
	float           error, work[1];
	magmaFloatComplex  c_neg_one = MAGMA_C_NEG_ONE;
	magmaFloatComplex *h_A, *h_R, *tau, *h_work, tmp[1];
	magmaFloatComplex *d_A;
	magma_int_t M, N, n2, lda, ldda, lwork, info, min_mn;
	magma_int_t ione     = 1;
	magma_int_t ISEED[4] = {0,0,0,1};

	magma_opts opts;
	parse_opts( argc, argv, &opts );

	printf("  M     N     CPU GFlop/s (sec)   MAGMA 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 ) {
			M = opts.msize[i];
			N = opts.nsize[i];
			min_mn = min(M, N);
			lda    = M;
			n2     = lda*N;
			ldda   = ((M+31)/32)*32;
			gflops = FLOPS_CGEQRF( M, N ) / 1e9;

			lwork = -1;
			lapackf77_cgeqrf(&M, &N, h_A, &M, tau, tmp, &lwork, &info);
			lwork = (magma_int_t)MAGMA_C_REAL( tmp[0] );

			TESTING_MALLOC_HOST(    tau, magmaFloatComplex, min_mn );
			TESTING_MALLOC_HOST(    h_A, magmaFloatComplex, n2     );
			TESTING_MALLOC_HOST(    h_R, magmaFloatComplex, n2     );
			TESTING_MALLOC_DEV (    d_A, magmaFloatComplex, ldda*N );
			TESTING_MALLOC_HOST(    h_work, magmaFloatComplex, lwork  );

			/* Initialize the matrix */
			lapackf77_clarnv( &ione, ISEED, &n2, h_A );
			lapackf77_clacpy( MagmaUpperLowerStr, &M, &N, h_A, &lda, h_R, &lda );
			magma_csetmatrix( M, N, h_R, 0, lda, d_A, 0, ldda, queue );
			magma_cgeqrf2_mic( M, N, d_A, 0, ldda, tau, &info, queue);
			
			magma_csetmatrix( M, N, h_R, 0, lda, d_A, 0, ldda, queue );

			/* ====================================================================
			   Performs operation using MAGMA
			   =================================================================== */
			mic_time = magma_wtime();
			magma_cgeqrf2_mic( M, N, d_A, 0, ldda, tau, &info, queue);
			mic_time = magma_wtime() - mic_time;
			mic_perf = gflops / mic_time;
			if (info != 0)
				printf("magma_cgeqrf returned error %d.\n", (int) info);

			if ( opts.check ) {
				/* =====================================================================
				   Performs operation using LAPACK
				   =================================================================== */
				cpu_time = magma_wtime();
				lapackf77_cgeqrf(&M, &N, h_A, &lda, tau, h_work, &lwork, &info);
				cpu_time = magma_wtime() - cpu_time;
				cpu_perf = gflops / cpu_time;
				if (info != 0)
					printf("lapackf77_cgeqrf returned error %d.\n", (int) info);

				/* =====================================================================
				   Check the result compared to LAPACK
				   =================================================================== */
				magma_cgetmatrix( M, N, d_A, 0, ldda, h_R, 0, M, queue );
				error = lapackf77_clange("f", &M, &N, h_A, &lda, work);
				blasf77_caxpy(&n2, &c_neg_one, h_A, &ione, h_R, &ione);
				error = lapackf77_clange("f", &M, &N, h_R, &lda, work) / error;

				printf("%5d %5d   %7.2f (%7.2f)   %7.2f (%7.2f)   %8.2e\n",
						(int) M, (int) N, cpu_perf, cpu_time, mic_perf, mic_time, error );
			}
			else {
				printf("%5d %5d     ---   (  ---  )   %7.2f (%7.2f)     ---  \n",
						(int) M, (int) N, mic_perf, mic_time);
			}

			fflush(0);

			TESTING_FREE_HOST( tau );
			TESTING_FREE_HOST( h_A );
			TESTING_FREE_HOST( h_work );
			TESTING_FREE_HOST( h_R );
			TESTING_FREE_DEV( d_A );
		}
		if ( opts.niter > 1 ) {
			printf( "\n" );
		}
	}

	/* Shutdown */
	magma_queue_destroy( queue );
	magma_finalize();

	return 0;
}
