/*
    -- MAGMA (version 2.6.2) --
       Univ. of Tennessee, Knoxville
       Univ. of California, Berkeley
       Univ. of Colorado, Denver
       @date March 2022
       
       @author Azzam Haidar
       @author Stan Tomov
       @author Raffaele Solca
*/

#include "magma_internal.h"

#define applyQver 113

#ifdef __cplusplus
extern "C" {
#endif

// =============================================================================
// Auxiliary functions for 2-stage eigensolvers


/******************************************************************************/
void cmp_vals(magma_int_t n, double *wr1, double *wr2, double *nrmI, double *nrm1, double *nrm2)
{
    magma_int_t i;
    double curv, maxv, sumv;

    maxv = 0.0;
    sumv = 0.0;
    for (i = 0; i < n; ++i) {
        curv = fabs( wr1[i] - wr2[i]);
        sumv += curv;
        if (maxv < curv) maxv = curv;
    }

    *nrmI = maxv;
    *nrm1 = sumv;
    *nrm2 = sqrt( sumv );
}


/******************************************************************************/
void magma_bulge_findpos113(magma_int_t n, magma_int_t nb, magma_int_t Vblksiz, magma_int_t sweep, magma_int_t st, magma_int_t *myblkid)
{
    magma_int_t prevGblkid, mastersweep;
    magma_int_t locblknb   = 0;
    magma_int_t prevblkcnt = 0;
    magma_int_t myblknb    = 0;
    magma_int_t lstGblkid  = magma_ceildiv( n-1, Vblksiz ) - 1; //nbGblk-1;
    magma_int_t myGblkid   = sweep/Vblksiz;

    // go forward and for each Gblk(a column of blocks) before my Gblk compute its number of blk.

    //===================================================
    for (prevGblkid = lstGblkid; prevGblkid > myGblkid; prevGblkid--)
    {
        mastersweep  = prevGblkid * Vblksiz;
        if (prevGblkid == lstGblkid)
            locblknb = magma_ceildiv((n-(mastersweep+1)), nb);
        else
            locblknb = magma_ceildiv((n-(mastersweep+2)), nb);
        prevblkcnt   = prevblkcnt + locblknb;
    }
    //===================================================
    /*
    // for best performance, the if condiiton inside the loop
    // is only for prevblkid == lastblkid so I can unroll this
    // out of the loop and so remove the if condition.
    //===================================================
    // for prevGblkid == lstGblkid
    mastersweep  = lstGblkid * Vblksiz;
    locblknb     = magma_ceildiv((n-(mastersweep+1)), nb);
    prevblkcnt   = prevblkcnt + locblknb;
    // the remaining of the loop
    for (prevGblkid = lstGblkid-1; prevGblkid > myGblkid; prevGblkid--)
    {
        mastersweep  = prevGblkid * Vblksiz;
        locblknb     = magma_ceildiv((n-(mastersweep+2)), nb);
        prevblkcnt   = prevblkcnt + locblknb;
    }
    //===================================================
    */
    myblknb = magma_ceildiv((st-sweep), nb);
    *myblkid    = prevblkcnt + myblknb -1;
    //printf("voici sweep %d  lstGblkid %d  myGblkid %d  prevcnt %d  myblknb %d  myblkid %d\n", sweep, lstGblkid, myGblkid, prevblkcnt, myblknb, *myblkid );
}



/******************************************************************************/
void magma_bulge_findpos(magma_int_t n, magma_int_t nb, magma_int_t Vblksiz, magma_int_t sweep, magma_int_t st, magma_int_t *myblkid)
{
    magma_int_t locblknb, prevblkcnt, prevGblkid;
    magma_int_t myblknb, nbprevGblk, mastersweep;

    locblknb = 0;
    prevblkcnt   = 0;
    myblknb  = 0;

    nbprevGblk = sweep/Vblksiz;
    for (prevGblkid = 0; prevGblkid < nbprevGblk; prevGblkid++)
    {
        mastersweep  = prevGblkid * Vblksiz;
        locblknb = magma_ceildiv((n-(mastersweep+2)), nb);
        prevblkcnt   = prevblkcnt + locblknb;
    }
    myblknb = magma_ceildiv((st-sweep), nb);
    *myblkid    = prevblkcnt + myblknb -1;
}


/******************************************************************************/
void magma_bulge_findVTAUpos(magma_int_t n, magma_int_t nb, magma_int_t Vblksiz, magma_int_t sweep, magma_int_t st, magma_int_t ldv,
                             magma_int_t *Vpos, magma_int_t *TAUpos)
{
    magma_int_t myblkid;
    magma_int_t locj = sweep%Vblksiz;

    if (applyQver == 113)
        magma_bulge_findpos113(n, nb, Vblksiz, sweep, st, &myblkid);
    else
        magma_bulge_findpos(n, nb, Vblksiz, sweep, st, &myblkid);

    *Vpos   = myblkid*Vblksiz*ldv + locj*ldv + locj;
    *TAUpos = myblkid*Vblksiz + locj;
}


/******************************************************************************/
void magma_bulge_findVTpos(magma_int_t n, magma_int_t nb, magma_int_t Vblksiz, magma_int_t sweep, magma_int_t st, magma_int_t ldv, magma_int_t ldt,
                           magma_int_t *Vpos, magma_int_t *Tpos)
{
    magma_int_t myblkid;
    magma_int_t locj = sweep%Vblksiz;

    if (applyQver == 113)
        magma_bulge_findpos113(n, nb, Vblksiz, sweep, st, &myblkid);
    else
        magma_bulge_findpos(n, nb, Vblksiz, sweep, st, &myblkid);


    *Vpos   = myblkid*Vblksiz*ldv + locj*ldv + locj;
    *Tpos   = myblkid*Vblksiz*ldt + locj*ldt + locj;
}


/******************************************************************************/
void magma_bulge_findVTAUTpos(magma_int_t n, magma_int_t nb, magma_int_t Vblksiz, magma_int_t sweep, magma_int_t st, magma_int_t ldv, magma_int_t ldt,
                           magma_int_t *Vpos, magma_int_t *TAUpos, magma_int_t *Tpos, magma_int_t *blkid)
{
    magma_int_t myblkid;
    magma_int_t locj = sweep%Vblksiz;

    if (applyQver == 113)
        magma_bulge_findpos113(n, nb, Vblksiz, sweep, st, &myblkid);
    else
        magma_bulge_findpos(n, nb, Vblksiz, sweep, st, &myblkid);


    *Vpos   = myblkid*Vblksiz*ldv + locj*ldv + locj;
    *TAUpos = myblkid*Vblksiz     + locj;
    *Tpos   = myblkid*Vblksiz*ldt + locj*ldt + locj;
    *blkid  = myblkid;
}


/******************************************************************************/
magma_int_t magma_bulge_get_blkcnt(magma_int_t n, magma_int_t nb, magma_int_t Vblksiz)
{
    magma_int_t colblk, nbcolblk;
    magma_int_t myblknb, mastersweep;

    magma_int_t blkcnt = 0;
    nbcolblk = magma_ceildiv((n-1), Vblksiz);
    for (colblk = 0; colblk<nbcolblk; colblk++)
    {
        mastersweep = colblk * Vblksiz;
        if (colblk == (nbcolblk-1))
            myblknb = magma_ceildiv((n-(mastersweep+1)), nb);
        else
            myblknb = magma_ceildiv((n-(mastersweep+2)), nb);
        blkcnt      = blkcnt + myblknb;
        //printf("voici  nbcolblk %d    master sweep %d     blkcnt %d\n", nbcolblk, mastersweep, *blkcnt);
    }
    return blkcnt;
}


/******************************************************************************/
magma_int_t magma_bulge_getlwstg1(magma_int_t n, magma_int_t nb, magma_int_t *lda2)
{
lda2[0] = 2*nb; //nb+1+nb-1
return n*lda2[0];
}


// =============================================================================
// Old functions

/******************************************************************************/
void findVTpos(magma_int_t N, magma_int_t NB, magma_int_t Vblksiz, magma_int_t sweep, magma_int_t st, magma_int_t *Vpos, magma_int_t *TAUpos, magma_int_t *Tpos, magma_int_t *myblkid)
{
    // to be able to use and compare with the old reduction function.
    // route the old function to the new ones because the changes are done on the new function.
    magma_int_t ldv = NB + Vblksiz;
    magma_int_t ldt = Vblksiz;
    magma_bulge_findVTAUTpos(N,  NB, Vblksiz,  sweep,  st,  ldv, ldt,
                           Vpos, TAUpos, Tpos, myblkid);
    return;



    magma_int_t locblknb, prevblkcnt, prevGblkid;
    magma_int_t myblknb, nbprevGblk, mastersweep;
    magma_int_t blkid, locj, LDV;
    locblknb = 0;
    prevblkcnt   = 0;
    myblknb  = 0;

    nbprevGblk = sweep/Vblksiz;
    for (prevGblkid = 0; prevGblkid < nbprevGblk; prevGblkid++)
    {
        mastersweep  = prevGblkid * Vblksiz;
        locblknb = magma_ceildiv((N-(mastersweep+2)), NB);
        prevblkcnt   = prevblkcnt + locblknb;
    }
    myblknb = magma_ceildiv((st-sweep), NB);
    blkid       = prevblkcnt + myblknb -1;
    locj        = sweep%Vblksiz;
    LDV         = NB + Vblksiz;

    *myblkid= blkid;
    *Vpos   = blkid*Vblksiz*LDV  + locj*LDV + locj;
    *TAUpos = blkid*Vblksiz + locj;
    *Tpos   = blkid*Vblksiz*Vblksiz + locj*Vblksiz + locj;
    //printf("voici  blkid  %d  locj %d  vpos %d tpos %d\n", blkid, locj, *Vpos, *Tpos);
}


/******************************************************************************/
void findVTsiz(magma_int_t N, magma_int_t NB, magma_int_t Vblksiz, magma_int_t *blkcnt, magma_int_t *LDV)
{
    magma_int_t colblk, nbcolblk;
    magma_int_t myblknb, mastersweep;

    *blkcnt   = 0;
    nbcolblk = magma_ceildiv((N-1), Vblksiz);
    for (colblk = 0; colblk<nbcolblk; colblk++)
    {
        mastersweep = colblk * Vblksiz;
        if (colblk == (nbcolblk-1))
            myblknb = magma_ceildiv((N-(mastersweep+1)), NB);
        else
            myblknb = magma_ceildiv((N-(mastersweep+2)), NB);

        *blkcnt      = *blkcnt + myblknb;
        //printf("voici  nbcolblk %d    master sweep %d     blkcnt %d\n", nbcolblk, mastersweep, *blkcnt);
    }
    *LDV = NB+Vblksiz;
}

#ifdef __cplusplus
}  // extern "C"
#endif
