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

/**
 *
 * 	@file kdspmv.c
 *
 * 	@brief LASs-DSSs kdspmv routine.
 *
 * 	LASs-DSSs is a software package provided by:
 * 	Barcelona Supercomputing Center - Centro Nacional de Supercomputacion
 *
 * 	@author Sandra Catalán sandra.catalan@bsc.es 
 * 	@author Pedro Valero-Lara pedro.valero@bsc.es 
 * 	@date 2019-05-30
 * 	@reviewer
 * 	@modified 
 *
 **/

/**
 *  
 *	@ingroup DSSs
 *   
 *	Performs the sparse matrix-vector operation with the CSR format:
 *
 *		Y = ALPHA * A * X + BETA * Y
 *
 *	where ALPHA and BETA are scalars, X and Y are vectors, and 
 *  A is a sparse matrix stored in the next three vectors 
 *  VAL_A, COL_IND_A and ROW_PTR_A according to CSR format.
 *
 **/

/**
 *    
 *	@param[in]
 *  M   			int.
 *	    			M specifies the number of rows of A.
 *
 *	@param[in]
 *  N   			int.
 *	    			N specifies the number of columns of A.
 *
 *	@param[in]
 *  ALPHA   		double.
 *
 *	@param[in]
 *  CSR_VAL_A		double *.
 *	       			VAL_A is a pointer to a vector which specifies the non-zero 
 *          		values of the original matrix A. 
 *   
 *	@param[in]
 *  CSR_ROW_PTR_A   unsigned int *.
 * 			    	ROW_PTR_A is a pointer to a vector which specifies 
 *					the number of values that A contains in each row of 
 *					the original matrix.
 *
 *	@param[in]
 *  CSR_COL_IND_A  	unsigned int *.
 * 			    	COL_IND_A is a pointer to a vector which specifies 
 *					the column index of each value of A in the original matrix. 
 *
 *  @param[in]
 *  X       		double *.
 *          		X is a pointer to a vector of dimension N. 
 *
 *  @param[in]
 *  BETA       		double.
 *
 *	@param[in, out]
 *  Y  				double *.
 *          		Y is a pointer to a vector of dimension M. On exit, 
 *					Y is overwritten by the sparse matrix-vector result. 
 *   
 *
 **/

/**
 *
 *	@retval Success sucessful exit
 *	@retval NoSuccess unsucessful exit
 *
 **/

/**
 * 
 * @sa dsss_dspmv
 *
 **/

enum LASS_RETURN kdspmv ( int M, int N, 
		double ALPHA, 
		const double *VAL_A, const int *ROW_PTR_A, const int *COL_IND_A, 
		const double *X, 
		double BETA, 
		double *Y ) 
{

	// Local variables
	double svalue = 0.0, value = 0.0;
	int max = 0, col = 0;
	int i, x;
	int chunksize = M;
    int factor = 1;

	if ( M / ( factor * NUM_CORES ) > 0)
		chunksize = M / ( factor * NUM_CORES ) ;

	#pragma omp taskloop private(svalue, max, value, col, i) \
						 grainsize(chunksize) label(spmv)
	for ( x = 0; x < M; x++ )
	{
		svalue = 0.0;
		max = ROW_PTR_A[x + 1] - ROW_PTR_A[x];
			for( i = 0; i < max; i++ )
			{
				value = VAL_A[ROW_PTR_A[x] + i];
				col = COL_IND_A[ROW_PTR_A[x] + i];
				svalue += value * X[col] * ALPHA;
			}
			Y[x] = svalue + Y[x] * BETA;
	}

	return Success;

}
