#include "../include/lass.h"

/**
 *
 *  @file isss_test_dcg.c
 *
 *  @brief LASs-ISSs isss_test_dcg routine.
 *
 *  LASs-ISSs is a software package provided by:
 *  Barcelona Supercomputing Center - Centro Nacional de Supercomputacion
 *
 *  @author Sandra Catalán Pallarés sandra.catalan@bsc.es
 *  @author Pedro Valero-Lara pedro.valero@bsc.es
 *  @date 2019-02-12
 *  @reviewer 
 *  @modified 
 *
 **/

/**
 *  
 *  @ingroup DDSs
 *   
 *  main:
 *  Performs the testing of the ddss_dgtsv routine. 
 *
 **/

/**
 *
 *  @sa isss_dcg
 *  @sa kdcg
 *
 **/

int main( int argc, char const *argv[] )
{

	if ( argc < 2 || argc > 2 )
	{
		fprintf( stderr, "Usage: ./test_dcg MATRIB.mtx\n" );
		return NoSuccess;
	}

	// Local variables
	int i;
	int j;
	int row_elements;
	int processed_elements;
	int m;
	int m1;
	int n;
	int nnz;
	double *CSR_VAL_A;
	int *CSR_ROW_PTR_A;
	int *CSR_COL_IND_A;
	double *B;
	double *X;
	double *CSR_VAL_A_ref;
	int *CSR_ROW_PTR_A_ref;
	int *CSR_COL_IND_A_ref;
	double *B_ref;
	double *X_ref;
	double *CSR_VAL_A_test;
	int *CSR_ROW_PTR_A_test;
	int *CSR_COL_IND_A_test;
	double *COO_VAL_A;
	int *COO_ROW_PTR_A;
	int *COO_COL_IND_A;
	double *B_test;
	double *X_test;
	double *B_error;
	double error;
	double max_error;
	double count_error;	
	struct timeval start, end;
	double time_ref;
	double time;
	enum LASS_RETURN ret;
	int elems;
	int k;

	max_error = 0.0;
	count_error = 0.0;

    n = m = atoi(argv[1]);
	
	nnz = 4 * n - 2;

 	FILE *fp;
    fp = fopen("/gpfs/scratch/bsc15/bsc15379/matricesCG/matrix_6000000.txt", "r");

    if ( fp == NULL){
        printf("Error Reading File. Please use generate_matrix to create a matrix file\n");
        exit (0);
    }
    
	fscanf(fp, "%d\t", &nnz );
	fscanf(fp, "%d\t", &m1 );
	fscanf(fp, "%d\t", &nnz );
	fscanf(fp, "\n");

	m = m1-1;
	n = m;
 
	// Vector allocation
	CSR_VAL_A       = ( double * ) calloc( nnz, sizeof( double ));
	CSR_ROW_PTR_A   = ( int * ) malloc( sizeof( int ) * (m+1) );
	CSR_COL_IND_A   = ( int * ) malloc( sizeof( int ) * nnz );
	B               = ( double * ) malloc( sizeof( double ) * m );
	X               = ( double * ) malloc( sizeof( double ) * m );

	CSR_VAL_A_ref       = ( double * ) malloc( sizeof( double ) * nnz );
	CSR_ROW_PTR_A_ref   = ( int * ) malloc( sizeof( int ) * (m+1) );
	CSR_COL_IND_A_ref   = ( int * ) malloc( sizeof( int ) * nnz );
	B_ref               = ( double * ) malloc( sizeof( double ) * m );
	X_ref               = ( double * ) malloc( sizeof( double ) * m );

	CSR_VAL_A_test       = ( double * ) malloc( sizeof( double ) * nnz );
	CSR_ROW_PTR_A_test   = ( int * ) malloc( sizeof( int ) * (m+1) );
	CSR_COL_IND_A_test   = ( int * ) malloc( sizeof( int ) * nnz );
	B_test               = ( double * ) malloc( sizeof( double ) * m );
	X_test               = ( double * ) malloc( sizeof( double ) * m );

	B_error				 = ( double * ) malloc( sizeof( double ) * m);


    for ( i = 0; i < nnz; i++ )
	{
        fscanf(fp, "%lf\t", &CSR_VAL_A[i] );
	}
	fscanf(fp, "\n");
	
    for ( i = 0; i < m + 1; i++ )
	{
        fscanf(fp, "%d\t", &CSR_ROW_PTR_A[i] );	
	}
	fscanf(fp, "\n");

    for ( i = 0; i < nnz; i++ )
	{
        fscanf(fp, "%d\t", &CSR_COL_IND_A[i] );	
	}
	fscanf(fp, "\n");

	fclose(fp);

	for ( i = 0; i < m; i++ )
	{
		B[i] = (double)  rand() / (double) RAND_MAX ;
		X[i] = 0.0; 
	}
	
	memcpy( CSR_VAL_A_ref, CSR_VAL_A, nnz * sizeof( double ) );
	memcpy( CSR_ROW_PTR_A_ref, CSR_ROW_PTR_A, ( m + 1 ) * sizeof( int ) );
	memcpy( CSR_COL_IND_A_ref, CSR_COL_IND_A, nnz * sizeof( int ) );
	memcpy( B_ref, B, m * sizeof( double ) );
	memcpy( X_ref, X, m * sizeof( double ) );

	memcpy( CSR_VAL_A_test, CSR_VAL_A, nnz * sizeof( double ) );
	memcpy( CSR_ROW_PTR_A_test, CSR_ROW_PTR_A, ( m + 1 ) * sizeof( int ) );
	memcpy( CSR_COL_IND_A_test, CSR_COL_IND_A, nnz * sizeof( int ) );
	memcpy( B_test, B, m * sizeof( double ) );
	memcpy( X_test, X, m * sizeof( double ) );

	memcpy( B_error, B, m * sizeof( double ) );

	ret = isss_dcg( m, 
					CSR_VAL_A_test, CSR_ROW_PTR_A_test,
					CSR_COL_IND_A_test, B_test,
					X_test );

	if ( ret == NoSuccess )
		return ret;	

	memcpy( CSR_VAL_A, CSR_VAL_A_ref, nnz * sizeof( double ) );
	memcpy( CSR_ROW_PTR_A, CSR_ROW_PTR_A_ref, ( m + 1 ) * sizeof( int ) );
	memcpy( CSR_COL_IND_A, CSR_COL_IND_A_ref, nnz * sizeof( int ) );
	memcpy( B, B_ref, m * sizeof( double ) );
	memcpy( X, X_ref, m * sizeof( double ) );
	
	gettimeofday( &start, NULL );

	ret = isss_dcg( m, 
					CSR_VAL_A, CSR_ROW_PTR_A,
					CSR_COL_IND_A, B,
					X );

	gettimeofday( &end, NULL );

	if ( ret == NoSuccess )
		return ret;	

	// TIME consumed by isss_dcg
	time = ( double ) (((end.tv_sec * 1e6 + end.tv_usec)
				- (start.tv_sec * 1e6 + start.tv_usec)) / 1e6);

    dspmvseq( m, n, 1.0,
				CSR_VAL_A, CSR_ROW_PTR_A,
				CSR_COL_IND_A, X,
				0.0, B_error );

	// Error computation
	for ( i = 0; i < m; i++ )
	{
		error = fabs( B_error[i] - B_ref[i] );
		
		if ( max_error < error )
		{
			max_error = error;
		}
		count_error += error;
	}

	fprintf( stdout, "Max. error = %1.2f\n", max_error );
	fprintf( stdout, "Av. error = %1.2f\n", count_error / m );
	fprintf( stdout, "ISSs_DCG TIME(s) = %1.2e\n", time );


	free( CSR_VAL_A );
	free( CSR_ROW_PTR_A );
	free( CSR_COL_IND_A );
	free( B );
	free( X );
	free( CSR_VAL_A_test );
	free( CSR_ROW_PTR_A_test );
	free( CSR_COL_IND_A_test );
	free( B_test );
	free( X_test );
	free( CSR_VAL_A_ref );
	free( CSR_ROW_PTR_A_ref );
	free( CSR_COL_IND_A_ref );
	free( B_ref );
	free( X_ref );
	
	return Success;

}
