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

/**
 *
 * 	@file ddss_dtrsm.c
 *
 * 	@brief LASs-DDSs ddss_dtrsm 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 2017-12-14
 * 	@reviewer 
 * 	@modified 
 *
 **/

/**
 *  
 *	@ingroup DDSS
 *   
 *	Solves one of the matrix equations:
 *
 *		op( A ) * X = ALPHA * B, or X * op( A ) = ALPHA * B
 *
 *	where op( A ) is one of:
 *
 *		op( A ) = A      or
 *		op( A ) = A**T 
 *	
 *	ALPHA is a scalar, X and B are M by N matrices, A is a unit, or non-unit,
 *	upper or lower triangular matrix. The matrix X is overwritten on B
 *
 **/

/**
 *	
 * 	@param[in]
 *	SIDE	enum DDSS_SIDE.
 *	        SIDE specifies the position of the triangular A matrix in 
 *			the operations:
 *      	- Left:      op( A ) * X = ALPHA * B.
 *       	- Right:     X * op( A ) = ALPHA * B.
 *	
 *	@param[in]
 *	UPLO	enum DDSS_UPLO.
 *	    	UPLO specifies the form of A is stored:
 *       	- Lower: Lower triangle of A is stored. The upper traingular part is
 *       	not referenced.
 *      	- Upper: Upper triangle of A is stored. The lower triangular part is
 *      	not referenced.
 *  
 *  @param[in]
 *	TRANS_A	enum DDSS_TRANS.
 *	        TRANS_A specifies the form of op( A ) to be used:  
 *      	- NoTrans:   op( A ) = A.
 *       	- Trans:     op( A ) = A**T.
 *       	
 *  @param[in]
 *	DIAG	enum DDSS_DIAG.
 *	        DIAG specifies whether or not A is unit triangular as follows:
 *      	- Unit:      A is assumed to be unit triangular.
 *       	- NonUnit:   A is not assumed to be unit triangular.
 *       	
 *	@param[in]
 *	M       int.
 *			M specifies the number of rows of B. M must be at least zero.
 *
 *	@param[in]
 *	N       int.
 *          N specifies the number of columns of B.  N 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 K by K, where K is M when 
 *          SIDE = Left and is N otherwise.
 *			When UPLO = Uppper the strictly lower triangular part of A is not
 *			referenced and when UPLO = Lower the strictly upper triangular part
 *			of A is not referenced.
 *          Note that when DIAG = Unit, the diagonal elements of A are not 
 *          referenced either, but are assumed to be unity.
 *
 *  @param[in]
 *  LDA     int.
 *          LDA specifies the number of columns of A ( row-major order ).
 *          When SIDE = Left then LDA must be at least  max( 1, M ), otherwise
 *          LDA must be at least max( 1, N ).
 *   
 *	@param[in, out]
 *  B  		double *.
 * 		    B is a pointer to a matrix of dimension M by N. 
 *			On exit the matrix B is overwritten by the solution matrix X.
 *   
 *	@param[in]
 *  LDB     int.
 * 		    LDB specifies the number of columns of B ( row-major order ).
 *          LDB must be at least max( 1, N ).
 *
 **/

/**
 *
 *	@sa kdtrsm
 *
 **/

int ddss_dtrsm( enum DDSS_SIDE SIDE, enum DDSS_UPLO UPLO,
		enum DDSS_TRANS TRANS_A, enum DDSS_DIAG DIAG, 
		int M, int N,
		const double ALPHA, double* A, int LDA, 
							double *B, int LDB ) 
{

	// Local variables
	int nA;
	
	// Argument checking
	if ( ( SIDE != Left ) && ( SIDE != Right ) ) 
	{
		fprintf( stderr, "Illegal value of SIDE, in ddss_dtrsm code\n" );
		return NoSuccess;
	}

	if ( ( UPLO != Upper ) && ( UPLO != Lower ) ) 
	{
		fprintf( stderr, "Illegal value of UPLO, in ddss_dtrsm code\n" );
		return NoSuccess;
	}

	if ( ( TRANS_A != NoTrans ) && ( TRANS_A != Trans ) ) 
	{
		fprintf( stderr, "Illegal value of TRANS_A, in ddss_dtrsm code\n" );
		return NoSuccess;
	}

	if ( ( DIAG != Unit ) && ( DIAG != NonUnit ) ) 
	{
		fprintf( stderr, "Illegal value of DIAG, in ddss_dtrsm code\n" );
		return NoSuccess;
	}

	if ( M < 0 ) 
	{
		fprintf( stderr, "Illegal value of M, in ddss_dtrsm code\n" );
		return NoSuccess;
	}

	if ( N < 0 ) 
	{
		fprintf( stderr, "Illegal value of N, in ddss_dtrsm code\n" );
		return NoSuccess;
	}

	if ( SIDE == Left ) 
	{
		nA = M;
	} 
	else 
	{
		nA = N;
	}

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

	if ( LDB < MAX( 1, N ) ) 
	{
		fprintf( stderr, "Illegal value of LDB, in ddss_dtrsm code\n" );
		return NoSuccess;
	}

	// Quick return
	if ( M == 0 || N == 0 )
	{
		return Success;
	}

	return kdtrsm( SIDE, UPLO, 
				   TRANS_A, DIAG, 
				   M, N, 
				   ALPHA, A, LDA, 
						  B, LDB );

}

