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

/**
 *
 * 	@file ddss_dsyr2k.c
 *
 * 	@brief LASs-DDSs ddss_dsyr2k routine.
 *
 * 	LASs-DDSs is a software package provided by:
 * 	Barcelona Supercomputing Center - Centro Nacional de Supercomputacion
 *
 * 	@author Pedro Valero-Lara   pedro.valero@bsc.es
 * 	@author Boro Sofranac       boro.sofranac@bsc.es
 * 	@date 2018-02-21
 * 	@reviewer 
 * 	@modified 
 *
 **/

/**
 *  
 *	@ingroup DDSS
 *   
 *	Performs one of the symmetric rank 2k operations:
 *
 *		C = ALPHA * A * B**T + ALPHA * B * A**T + BETA * C or
 *		C = ALPHA * A**T * B + ALPHA * B**T * A + BETA * C
 *	
 *	ALPHA and BETA are scalars, C is an N by N symmetric matrix and A and B are
 *	N by K matrices in the first case and K by N matrices in the second case.
 *
 **/

/**
 *	@param[in]
 *	UPLO	enum DDSS_UPLO.
 *	    	UPLO specifies the form in which C is stored:
 *       	- Lower: Lower triangular part of C is stored. The upper traingular
 *       	part is not referenced.
 *      	- Upper: Upper triangular part of C is stored. The lower triangular
 *      	part is not referenced.
 *  
 *  @param[in]
 *	TRANS	enum DDSS_TRANS.
 *	        TRANS specifies the operation to be performed as follows:  
 *      	- NoTrans:   C = ALPHA * A * B**T + ALPHA * B * A**T + BETA * C
 *       	- Trans:     C = ALPHA * A**T * B + ALPHA * B**T * A + BETA * C
 *       	
 *	@param[in]
 *	N       int.
 *			N specifies the order of matrix C. N must be at least zero.
 *
 *	@param[in]
 *	K       int.
 *          With TRANS = NoTrans, K specifies the number of columns of the
 *          matrices A and B, and with TRANS = Trans, K specifies the number of
 *          rows of the matrices A and B. K must be at least zero.
 *    
 *	@param[in]
 *  ALPHA   double.
 *   		ALPHA specifies the scalar alpha.
 *   		
 *	@param[in]
 *  A  		double *.
 *          A is a pointer to a matrix of dimension Na ( rows ) by Ka  
 *			( columns ), where Na is N and Ka is K when TRANS = NoTrans, 
 *			and Na is K and Ka is N otherwise.
 *
 *  @param[in]
 *  LDA     int.
 *          LDA specifies the number of columns of A ( row-major order ).
 *          When TRANS = NoTrans then LDA must be at least  max( 1, K ),
 *          otherwise LDA must be at least max( 1, N ).
 *          
 *	@param[in]
 *  B  		double *.
 *          B is a pointer to a matrix of dimension Nb ( rows ) by Kb  
 *			( columns ), where Nb is N and Kb is K when TRANS = NoTrans, 
 *			and Nb is K and Kb is N otherwise.
 *			
 *  @param[in]
 *  LDB     int.
 *          LDB specifies the number of columns of B ( row-major order ).
 *          When TRANS = NoTrans then LDB must be at least  max( 1, K ),
 *          otherwise LDB must be at least max( 1, N ).
 *          
 *	@param[in]
 *  BETA    double.
 *   		BETA specifies the scalar beta.
 *   
 *	@param[in, out]
 *  C  		double *.
 * 		    C is a pointer to a matrix of dimension N by N. 
 *			When UPLO = Uppper the strictly lower triangular part of C is not
 *			referenced. On exit, the upper triangular part of C is overwritten
 *			by the upper triangular part of the updated solution matrix C.
 *			When UPLO = Lower the strictly upper triangular part of C is not
 *			referenced. On exit, the lower triangular part of C is overwritten
 *			by the lower triangular part of the updated solution matrix C.
 *   
 *	@param[in]
 *  LDC     int.
 * 		    LDC specifies the number of columns of C ( row-major order ).
 *          LDC must be at least max( 1, N ).
 *
 **/

/**
 *
 *	@sa kdsyr2k
 *
 **/

int ddss_dsyr2k( enum DDSS_UPLO UPLO, enum DDSS_TRANS TRANS, 
		int N, int K,
        const double ALPHA, double *A, int LDA,
						    double *B, int LDB,
    	const double BETA,  double *C, int LDC )
{
	// Local variables
	int nA, nB;
	
	// Argument checking
	if ( ( UPLO != Upper ) && ( UPLO != Lower ) ) 
	{
		fprintf( stderr, "Illegal value of UPLO, in ddss_dsyr2k code\n" );
		return NoSuccess;
	}
	
	if ( ( TRANS != NoTrans ) && ( TRANS != Trans ) )
	{
		fprintf( stderr, "Illegal value of TRANS, in ddss_dsyr2k code\n" );
		return NoSuccess;
	}
	
	if ( N < 0 )
	{
		fprintf( stderr, "Illegal value of N, in ddss_dsyr2k code\n" );
		return NoSuccess;
	}
		
	if ( K < 0 )
	{
		fprintf( stderr, "Illegal value of K, in ddss_dsyr2k code\n" );
		return NoSuccess;
	}
	
	if ( TRANS == NoTrans ) 
	{
		nA = nB = K;
	} 
	else 
	{
		nA = nB = N;
	}

	if ( LDA < MAX( 1, nA ) ) 
	{
		fprintf( stderr, "Illegal value of LDA, in ddss_dsyr2k code\n" );
		return NoSuccess;
	}
	
	if ( LDB < MAX( 1, nB ) ) 
	{
		fprintf( stderr, "Illegal value of LDB, in ddss_dsyr2k code\n" );
		return NoSuccess;
	}

	if ( LDC < MAX( 1, N ) ) 
	{
		fprintf( stderr, "Illegal value of LDC, in ddss_dsyr2k code\n" );
		return NoSuccess;
	}
	
	// Quick return
	 if ( N == 0 || ( ( ALPHA == 0.0 || K == 0 ) && BETA == 1.0 ) )
	 {
		 return Success;
	 }
	
	return kdsyr2k( UPLO, TRANS,
				    N, K,
				    ALPHA, A, LDA,
				   	       B, LDB,
				    BETA,  C, LDC );

}
