/*--------------------------------------------------
  rsdpa_pdpotrf.cpp
--------------------------------------------------*/
   
#include <rsdpa_pdpotrf.h>
// この並列版 Cholesky 分解は一般的なものではない
// 扱うのは下三角のみ
// また、それぞれの行は１つのプロセスでないと行けない
// つまり nb_ = m = n であるということ。
// もちろん mb_ は m 以下であれば等しくなくてもよい

int rpdpotrf(double* A,int* descA,int iam, int nprocs)
{
  int ictxt = descA[CTXT1_];
  int m     = descA[M1_];
  int mb    = descA[MB1_];
  int lld   = descA[LLD1_];
  // double pmem[1000];
  int PP = m/mb;
  int info = 0;
  // cout << "PP = " << PP << endl;
  for (int k=0; k<PP; ++k) {
    // cout << "iam = " << iam << endl;
    info = 0;
    if (k % nprocs == iam) {
      // ここで左上の細かいところを
      // Cholesky 分解する
      int QQ = k / nprocs;
      // iam の中では QQ 番目のブロック
      int index = k*mb*lld+QQ*mb;
      // A[index] が自分のところで分解するところ

      info = rATL_dpotrfL(mb,&A[index],lld);
      Cigebs2d(ictxt,"All"," ",1,1,(char*)&info,1);
    }
    else {
      Cigebr2d(ictxt,"All"," ",1,1,(char*)&info,1,k%nprocs,0);
    }
    // rMessage("info = " << info);  Cblacs_barrier(rMpiSt::ictxt,"All");
    if (info!=0) {
      return info+k*mb;
    }
    // pdlaprnt_(&m,&m,A,&IONE,&IONE,descA,&IZERO,&IZERO,
    //      "A = " , &ISTDOUT, pmem,4);

    // 分解し終わったら掛け算を繰り返して
    // 情報を伝搬させる
    int pp1 = m-((k+1)*mb);
    if (pp1 == 0) {
      break;
    }
    int ia1 = k*mb+1;
    int ja1 = k*mb+1;
    int ia2 = (k+1)*mb+1;
    int ja2 = k*mb+1;
    # if 0
    cout << " ia1 = " << ia1
	 << " ja1 = " << ja1
	 << " ia2 = " << ia2
	 << " ja2 = " << ja2
	 << " pp1 = " << pp1
	 << endl;
    #endif
    pdtrsm_("Right", "Lower", "Trans" , "NonDiag",
	    &pp1, &mb, &DONE,
	    A,&ia1,&ja1, descA, A, &ia2, &ja2, descA);
    // pdlaprnt_(&m,&m,A,&IONE,&IONE,descA,&IZERO,&IZERO,
    //	      "A2 = " , &ISTDOUT, pmem,5);
    pdsyrk_("Lower","NoTrans",
	    &pp1, &mb, &DMONE, A, &ia2, &ja2, descA,
	    &DONE,A, &ia2, &ia2, descA );
    // pdlaprnt_(&m,&m,A,&IONE,&IONE,descA,&IZERO,&IZERO,
    // 	      "A3 = " , &ISTDOUT, pmem,5);
  }
  // 右端の残りの分
  info = 0;
  int amari = m % mb;
  if (amari!=0) {
    if (iam == PP%nprocs) {
      // cout << "nokori iam = " << iam << endl;
      // ここが 最期の残りを処理する
      // この分だけコレスキー分解がのこっている
      int QQ = PP / nprocs;
      // iam の中では QQ 番目のブロック
      int index = PP*mb*lld+QQ*mb;
      // cout << "QQ = " << QQ << " index = " << index << endl;
      // A[index] が自分のところで分解するところ
      info = rATL_dpotrfL(amari,&A[index],lld);
      Cigebs2d(ictxt,"All"," ",1,1,(char*)&info,1);
    }
    else {
      Cigebr2d(ictxt,"All"," ",1,1,(char*)&info,1,PP%nprocs,0);
    }
  }
  // rMessage("info = " << info);  Cblacs_barrier(rMpiSt::ictxt,"All");
  if (info!=0) {
    return info+PP*mb;
  }
  return 0;
}
