#include "lu_internal.h"
#include "lu_list.h"
#include "lu_file.h"
lu_int lu_build_factors(struct lu *this)
{
const lu_int m = this->m;
const lu_int rank = this->rank;
const lu_int Lmem = this->Lmem;
const lu_int Umem = this->Umem;
const lu_int Wmem = this->Wmem;
const lu_int pad = this->pad;
const double stretch = this->stretch;
lu_int *pinv = this->pinv;
lu_int *qinv = this->qinv;
lu_int *pmap = this->pmap;
lu_int *qmap = this->qmap;
lu_int *pivotcol = this->pivotcol;
lu_int *pivotrow = this->pivotrow;
lu_int *Lbegin = this->Lbegin;
lu_int *Lbegin_p = this->Lbegin_p;
lu_int *Ltbegin = this->Ltbegin;
lu_int *Ltbegin_p = this->Ltbegin_p;
lu_int *Ubegin = this->Ubegin;
lu_int *Rbegin = this->Rbegin;
lu_int *Wbegin = this->Wbegin;
lu_int *Wend = this->Wend;
lu_int *Wflink = this->Wflink;
lu_int *Wblink = this->Wblink;
double *col_pivot = this->col_pivot;
double *row_pivot = this->row_pivot;
lu_int *Lindex = this->Lindex;
double *Lvalue = this->Lvalue;
lu_int *Uindex = this->Uindex;
double *Uvalue = this->Uvalue;
lu_int *Windex = this->Windex;
double *Wvalue = this->Wvalue;
lu_int *iwork1 = this->iwork1;
lu_int i, j, ipivot, jpivot, k, lrank, nz, Lnz, Unz, need, get, put, pos;
double pivot, min_pivot, max_pivot;
lu_int status = BASICLU_OK;
Lnz = Lbegin_p[rank];
Lnz -= rank;
Unz = Ubegin[rank];
need = 2*(Lnz+m);
if (Lmem < need)
{
this->addmemL = need-Lmem;
status = BASICLU_REALLOCATE;
}
need = Unz+m+1;
if (Umem < need)
{
this->addmemU = need-Umem;
status = BASICLU_REALLOCATE;
}
need = Unz + stretch*Unz + m*pad;
if (Wmem < need)
{
this->addmemW = need-Wmem;
status = BASICLU_REALLOCATE;
}
if (status != BASICLU_OK)
return status;
#ifndef NDEBUG
for (k = 0; k < m; k++)
pivotrow[k] = -1;
for (k = 0; k < m; k++)
pivotcol[k] = -1;
#endif
lrank = rank;
for (i = 0; i < m; i++)
{
if (pinv[i] < 0)
pinv[i] = lrank++;
pivotrow[pinv[i]] = i;
}
assert(lrank == m);
lrank = rank;
for (j = 0; j < m; j++)
{
if (qinv[j] < 0)
qinv[j] = lrank++;
pivotcol[qinv[j]] = j;
}
assert(lrank == m);
#ifndef NDEBUG
for (k = 0; k < m; k++)
assert(pivotrow[k] >= 0);
for (k = 0; k < m; k++)
assert(pivotcol[k] >= 0);
#endif
for (k = rank; k < m; k++)
col_pivot[pivotcol[k]] = 1.0;
put = Lbegin_p[rank];
for (k = rank; k < m; k++)
{
Lindex[put++] = -1;
Lbegin_p[k+1] = put;
}
assert(Lbegin_p[m] == Lnz+m);
for (i = 0; i < m; i++)
Lbegin[i] = Lbegin_p[pinv[i]];
memset(iwork1, 0, m*sizeof(lu_int));
for (get = 0; get < Lnz+m; get++)
{
if ((i = Lindex[get]) >= 0)
iwork1[i]++;
}
put = Lnz+m;
for (k = 0; k < m; k++)
{
i = pivotrow[k];
Ltbegin_p[k] = put;
Ltbegin[i] = put;
put += iwork1[i];
Lindex[put++] = -1;
iwork1[i]= Ltbegin_p[k];
}
assert(put == 2*(Lnz+m));
for (k = 0; k < m; k++)
{
ipivot = pivotrow[k];
for (get = Lbegin_p[k]; (i = Lindex[get]) >= 0; get++)
{
put = iwork1[i]++;
Lindex[put] = ipivot;
Lvalue[put] = Lvalue[get];
}
}
#ifndef NDEBUG
for (i = 0; i < m; i++)
assert(Lindex[iwork1[i]] == -1);
#endif
Rbegin[0] = 2*(Lnz+m);
lu_file_empty(m, Wbegin, Wend, Wflink, Wblink, Wmem);
memset(iwork1, 0, m*sizeof(lu_int));
put = 0;
if (rank == m)
{
for (k = 0; k < m; k++)
{
jpivot = pivotcol[k];
Wbegin[jpivot] = put;
nz = 0;
for (pos = Ubegin[k]; pos < Ubegin[k+1]; pos++)
{
j = Uindex[pos];
Windex[put] = j;
Wvalue[put++] = Uvalue[pos];
iwork1[j]++;
nz++;
}
Wend[jpivot] = put;
put += stretch*nz + pad;
lu_list_move(jpivot, 0, Wflink, Wblink, m, NULL);
}
}
else
{
Unz = 0;
for (k = 0; k < rank; k++)
{
jpivot = pivotcol[k];
Wbegin[jpivot] = put;
nz = 0;
for (pos = Ubegin[k]; pos < Ubegin[k+1]; pos++)
{
j = Uindex[pos];
if (qinv[j] < rank)
{
Windex[put] = j;
Wvalue[put++] = Uvalue[pos];
iwork1[j]++;
nz++;
}
}
Wend[jpivot] = put;
put += stretch*nz + pad;
lu_list_move(jpivot, 0, Wflink, Wblink, m, NULL);
Unz += nz;
}
for (k = rank; k < m; k++)
{
jpivot = pivotcol[k];
Wbegin[jpivot] = put;
Wend[jpivot] = put;
put += pad;
lu_list_move(jpivot, 0, Wflink, Wblink, m, NULL);
}
}
assert(put <= Wend[m]);
Wbegin[m] = put;
Uindex[0] = -1;
put = 1;
for (k = 0; k < m; k++)
{
j = pivotcol[k];
i = pivotrow[k];
nz = iwork1[j];
if (nz == 0)
{
Ubegin[i] = 0;
}
else
{
Ubegin[i] = put;
put += nz;
Uindex[put++] = -1;
}
iwork1[j] = Ubegin[i];
}
Ubegin[m] = put;
for (k = 0; k < m; k++)
{
jpivot = pivotcol[k];
i = pivotrow[k];
for (pos = Wbegin[jpivot]; pos < Wend[jpivot]; pos++)
{
j = Windex[pos];
put = iwork1[j]++;
assert(put >= 1);
Uindex[put] = i;
Uvalue[put] = Wvalue[pos];
}
}
#ifndef NDEBUG
for (j = 0; j < m; j++)
assert(Uindex[iwork1[j]] == -1);
#endif
for (k = 0; k < m; k++)
{
i = pivotrow[k];
j = pivotcol[k];
pmap[j] = i;
qmap[i] = j;
}
max_pivot = 0.0;
min_pivot = INFINITY;
for (i = 0; i < m; i++)
{
row_pivot[i] = col_pivot[qmap[i]];
pivot = fabs(row_pivot[i]);
max_pivot = fmax(pivot, max_pivot);
min_pivot = fmin(pivot, min_pivot);
}
memcpy(this->p, pivotrow, m*sizeof(lu_int));
this->min_pivot = min_pivot;
this->max_pivot = max_pivot;
this->pivotlen = m;
this->Lnz = Lnz;
this->Unz = Unz;
this->Rnz = 0;
return status;
}