/*

% This file is part of SeDuMi 1.1 by Imre Polik and Oleksandr Romanko
% Copyright (C) 2005 McMaster University, Hamilton, CANADA  (since 1.1)
%
% Copyright (C) 2001 Jos F. Sturm (up to 1.05R5)
%   Dept. Econometrics & O.R., Tilburg University, the Netherlands.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% Affiliation SeDuMi 1.03 and 1.04Beta (2000):
%   Dept. Quantitative Economics, Maastricht University, the Netherlands.
%
% Affiliations up to SeDuMi 1.02 (AUG1998):
%   CRL, McMaster University, Canada.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
% 02110-1301, USA

*/
#include "mex.h"
#include "blkchol.h"
/* ============================================================
   BACKWARD SOLVE:
   ============================================================ */
/* ************************************************************
   PROCEDURE bwsolve -- Solve y from L'*y = b, where
     L is lower-triangular.
   INPUT
     Ljc, Lir, Lpr - sparse lower triangular matrix
     xsuper - starting column in L for each (dense) supernode.
     nsuper - number of super nodes
   UPDATED
     y - full xsuper[nsuper]-vector, yOUTPUT = L' \ yINPUT.
   ************************************************************ */
void bwsolve(double *y, const mwIndex *Ljc, const mwIndex *Lir, const double *Lpr,
             const mwIndex *xsuper, const mwIndex nsuper)
{
  mwIndex jsup,j,inz,k;
  double yj, ljj;

  /* ------------------------------------------------------------
     For each supernode jsup:
     ------------------------------------------------------------ */
  j = xsuper[nsuper];      /* column after current snode (j=m)*/
  for(jsup = nsuper; jsup > 0; jsup--){
    for(k = 0; k < xsuper[jsup] - xsuper[jsup-1]; k++){
  /* ------------------------------------------------------------
     The equation L(:,j)'*yNEW = yOLD(j), yields
       y(j) -= L(j+1:m,j)'*y.
     ------------------------------------------------------------ */
      inz = Ljc[j-1];
      inz++;                        /* jump over diagonal entry */
      yj = realdot(Lpr+inz, y+j, k);
      for(inz += k; inz < Ljc[j]; inz++)
	yj += Lpr[inz] * y[Lir[inz]];
      y[--j] -= yj;
    }
  }
}

/* ************************************************************
   PROCEDURE partbwsolve -- Solve y from L(0:m-1,0:m-1)'*y = b, where
     L is lower-triangular.
   INPUT
     L=(ljc,lpr,xlindx,lindx) - sparse lower triangular matrix
     xsuper - starting column in L for each (dense) supernode.
     nsuper - number of super nodes (for NW-subblock)
     m  - order of L'- (sub) block, xsuper[nsuper-1] < m <= xsuper[nsuper]
       To solve with the complete L, choose m = xsuper[nsuper].
   UPDATED
     y - full m-vector, yOUT = L(0:m-1,0:m-1)'\yIN.
   ************************************************************ */
void partbwsolve(double *y, const mwIndex *ljc, const double *lpr,
             const mwIndex *xlindx, const mwIndex *lindx, const mwIndex *xsuper,
             const mwIndex nsuper, const mwIndex m)
{
  mwIndex jsup,j,inz,k,i, ixfirst,ixnz;
  double yj;
/* ------------------------------------------------------------
   For each supernode jsup:
   Let ixfirst point to the 1st row-subscript below current supernode.
   ------------------------------------------------------------ */
  j = m;           /* column/row after current entry */
  for(jsup = nsuper; jsup > 0; jsup--){
    ixfirst = xlindx[jsup-1] + (xsuper[jsup] - xsuper[jsup-1]);
/* ------------------------------------------------------------
   Case 1: L has sparse nonzeros below current supernode, but not
   beyond m:
   ------------------------------------------------------------ */
    if(ixfirst < xlindx[jsup])
      if(lindx[xlindx[jsup] - 1] < m)
        for(k = 0; j > xsuper[jsup-1]; k++){
  /* ------------------------------------------------------------
     The equation L(:,j)'*y=b(j), yields
       y(j) = b(j)-L(j+1:m,j)'*y.
     ------------------------------------------------------------ */
          inz = ljc[j-1] + 1;               /* jump over diagonal entry */
          yj = realdot(lpr+inz, y+j, k);
          for(inz += k, ixnz = ixfirst; inz < ljc[j]; inz++, ixnz++)
            yj += lpr[inz] * y[lindx[ixnz]];
          y[--j] -= yj;
        }
      else
/* ------------------------------------------------------------
   2nd CASE: L(:,j) has nonzeros beyond the requested order m,
   so use while i < m.
   ------------------------------------------------------------ */
        for(k = 0; j > xsuper[jsup-1]; k++){
          inz = ljc[j-1] + 1;               /* jump over diagonal entry */
          yj = realdot(lpr+inz, y+j, k);
          inz += k; ixnz = ixfirst;
          for(i=lindx[ixnz]; i < m; i = lindx[++ixnz])
            yj += lpr[inz++] * y[i];
          y[--j] -= yj;
        }
    else
/* ------------------------------------------------------------
   3rd CASE: L(:,j) has only nonzeros in snode jsup: purely dense.
   ------------------------------------------------------------ */
      for(k = 1, --j; j > xsuper[jsup-1]; k++){
        yj = realdot(lpr + ljc[j-1] + 1, y+j, k);
        y[--j] -= yj;
      }
  }
}
