/*
    -- micMAGMA (version 0.1) --
       Univ. of Tennessee, Knoxville
       Univ. of California, Berkeley
       Univ. of Colorado, Denver
       April 2012

       @generated s Fri Nov 22 14:21:15 2013
*/

#include <stdio.h>
#include "common_magma.h" 

// === Define what BLAS to use ============================================
//#define PRECISION_s
//#if (defined(PRECISION_s) || defined(PRECISION_d))
//  #define magma_sgemm magmablas_sgemm
//#endif
// === End defining what BLAS to use =======================================

magma_err_t
magma_slarfb_mic( magma_int_t side, magma_int_t trans, magma_int_t direct, magma_int_t storev,
                  magma_int_t m, magma_int_t n, magma_int_t k,
                  magmaFloat_ptr dV, size_t dV_offset,   magma_int_t ldv, 
                  magmaFloat_ptr dT, size_t dT_offset,   magma_int_t ldt,
                  magmaFloat_ptr dC, size_t dC_offset,   magma_int_t ldc, 
                  magmaFloat_ptr dwork, size_t dwork_offset, magma_int_t ldwork,
		  magma_queue_t queue)
{
/*  -- MAGMA (version 1.1) --
       Univ. of Tennessee, Univ. of California Berkeley
       November 2011

    Purpose
    =======
    SLARFB applies a real block reflector H or its transpose H^H to a
    REAL m by n matrix C, from the left.

    Arguments
    =========
    SIDE    (input) CHARACTER
            = 'L': apply H or H^H from the Left
            = 'R': apply H or H^H from the Right

    TRANS   (input) CHARACTER
            = 'N': apply H   (No transpose)
            = 'C': apply H^H (Conjugate transpose)

    DIRECT  (input) CHARACTER
            Indicates how H is formed from a product of elementary
            reflectors
            = 'F': H = H(1) H(2) . . . H(k) (Forward)
            = 'B': H = H(k) . . . H(2) H(1) (Backward)

    STOREV  (input) CHARACTER
            Indicates how the vectors which define the elementary
            reflectors are stored:
            = 'C': Columnwise
            = 'R': Rowwise

    M       (input) INTEGER
            The number of rows of the matrix C.

    N       (input) INTEGER
            The number of columns of the matrix C.

    K       (input) INTEGER
            The order of the matrix T (= the number of elementary
            reflectors whose product defines the block reflector).

    DV      (input) REAL array on the GPU, dimension
                (LDV,K) if STOREV = 'C'
                (LDV,M) if STOREV = 'R' and SIDE = 'L'
                (LDV,N) if STOREV = 'R' and SIDE = 'R'
            The matrix V. See further details.

    LDV     (input) INTEGER
            The leading dimension of the array V.
            If STOREV = 'C' and SIDE = 'L', LDV >= max(1,M);
            if STOREV = 'C' and SIDE = 'R', LDV >= max(1,N);
            if STOREV = 'R', LDV >= K.

    DT      (input) REAL array on the GPU, dimension (LDT,K)
            The triangular k by k matrix T in the representation of the
            block reflector.

    LDT     (input) INTEGER
            The leading dimension of the array T. LDT >= K.

    DC      (input/output) REAL array on the GPU, dimension (LDC,N)
            On entry, the m by n matrix C.
            On exit, C is overwritten by H*C, or H^H*C, or C*H, or C*H^H.

    LDC     (input) INTEGER
            The leading dimension of the array C. LDA >= max(1,M).

    WORK    (workspace) REAL array, dimension (LDWORK,K)

    LDWORK  (input) INTEGER
            The leading dimension of the array WORK.
            If SIDE == 'L', LDWORK >= max(1,N);
            if SIDE == 'R', LDWORK >= max(1,M);

    Further Details
    ===============

    The shape of the matrix V and the storage of the vectors which define
    the H(i) is best illustrated by the following example with n = 5 and
    k = 3.
    All elements including 0's and 1's are stored, unlike LAPACK.

    DIRECT = 'F' and STOREV = 'C':         DIRECT = 'F' and STOREV = 'R':

                 V = (  1  0  0 )                 V = (  1 v1 v1 v1 v1 )
                     ( v1  1  0 )                     (  0  1 v2 v2 v2 )
                     ( v1 v2  1 )                     (  0  0  1 v3 v3 )
                     ( v1 v2 v3 )
                     ( v1 v2 v3 )

    DIRECT = 'B' and STOREV = 'C':         DIRECT = 'B' and STOREV = 'R':

                 V = ( v1 v2 v3 )                 V = ( v1 v1  1  0  0 )
                     ( v1 v2 v3 )                     ( v2 v2 v2  1  0 )
                     (  1 v2 v3 )                     ( v3 v3 v3 v3  1 )
                     (  0  1 v3 )
                     (  0  0  1 )

    ===================================================================      */

    float c_zero    = MAGMA_S_ZERO;
    float c_one     = MAGMA_S_ONE;
    float c_neg_one = MAGMA_S_NEG_ONE;

    /* Function Body */
    if (m <= 0 || n <= 0) {
        return MAGMA_SUCCESS;
    }

    // opposite of trans
    //char transt;
	magma_int_t transt;
	//if (trans == 'N' || trans == 'n')
	if (trans == MagmaNoTrans)
		transt = MagmaTrans;
	else
		transt = MagmaNoTrans;

	// whether T is upper or lower triangular
	//char uplo;
	magma_int_t uplo;
	//if (direct == 'F' || direct == 'f')
	if (direct == MagmaForward)
		uplo = MagmaUpper;
	else
		uplo = MagmaLower;

	// whether V is stored transposed or not
	//    char notransV, transV;
	magma_int_t notransV, transV;
	//if (storev == 'C' || storev == 'c') {
	if (storev == MagmaColumnwise) {
		notransV = MagmaNoTrans;
		transV   = MagmaTrans;
	}
	else {
		notransV = MagmaTrans;
		transV   = MagmaNoTrans;
	}

	//if ( side  == 'l' || side  == 'L' ) {
	if ( side  == MagmaLeft ) {
		// Form H C or H^H C
		// Comments assume H C. When forming H^H C, T gets transposed via transt.

		// W = C^H V
		magma_sgemm( MagmaTrans, notransV,
				n, k, m,
				c_one,  dC,    dC_offset, ldc,
				dV,    dV_offset, ldv,
				c_zero, dwork, dwork_offset, ldwork, queue);

		// W = W T^H = C^H V T^H
		magma_strmm( MagmaRight, uplo, transt, MagmaNonUnit,
				n, k,
				c_one, dT,    dT_offset, ldt,
				dwork, dwork_offset, ldwork, queue);

		// C = C - V W^H = C - V T V^H C = (I - V T V^H) C = H C
		magma_sgemm( notransV, MagmaTrans,
				m, n, k,
				c_neg_one, dV,    dV_offset, ldv,
				dwork, dwork_offset, ldwork,
				c_one,     dC,    dC_offset, ldc, queue);
	}
	else {
		// Form C H or C H^H
		// Comments assume C H. When forming C H^H, T gets transposed via trans.

		// W = C V
		magma_sgemm( MagmaNoTrans, notransV,
				m, k, n,
				c_one,  dC,    dC_offset, ldc,
				dV,    dV_offset, ldv,
				c_zero, dwork, dwork_offset, ldwork, queue);

		// W = W T = C V T
		magma_strmm( MagmaRight, uplo, trans, MagmaNonUnit,
				m, k,
				c_one, dT,    dT_offset, ldt,
				dwork, dwork_offset, ldwork, queue);

		// C = C - W V^H = C - C V T V^H = C (I - V T V^H) = C H
		magma_sgemm( MagmaNoTrans, transV,
				m, n, k,
				c_neg_one, dwork, dwork_offset, ldwork,
				dV,    dV_offset, ldv,
				c_one,     dC,    dC_offset, ldc, queue);
	}

	return MAGMA_SUCCESS;
} /* magma_slarfb */

