use crate::lu::file::file_empty;
use crate::lu::list::list_move;
use crate::lu::lu::*;
use crate::LUInt;
use crate::Status;
pub(crate) fn build_factors(lu: &mut LU) -> Status {
let m = lu.m;
let rank = lu.rank;
let l_mem = lu.l_mem;
let u_mem = lu.u_mem;
let w_mem = lu.w_mem;
let pad = lu.pad;
let stretch = lu.stretch;
let pivotcol = &mut pivotcol!(lu);
let pivotrow = &mut pivotrow!(lu);
let l_begin = &mut l_begin!(lu);
let lt_begin = &mut lt_begin!(lu);
let lt_begin_p = &mut lt_begin_p!(lu);
let r_begin = &mut r_begin!(lu);
let l_index = &mut lu.l_index;
let l_value = &mut lu.l_value;
let u_index = &mut lu.u_index;
let u_value = &mut lu.u_value;
let w_index = &mut lu.w_index;
let w_value = &mut lu.w_value;
let iwork1 = &mut iwork1!(lu);
let mut status = Status::OK;
let mut l_nz = lu.l_begin_p[rank as usize] as usize;
l_nz -= rank; let mut u_nz = lu.u_begin[rank as usize] as usize;
let need = 2 * (l_nz + m);
if l_mem < need {
lu.addmem_l = need - l_mem;
status = Status::Reallocate;
}
let need = u_nz + m + 1;
if u_mem < need {
lu.addmem_u = need - u_mem;
status = Status::Reallocate;
}
let need = u_nz + (stretch * u_nz as f64) as usize + m * pad;
if w_mem < need {
lu.addmem_w = need - w_mem;
status = Status::Reallocate;
}
if status != Status::OK {
return status;
}
if cfg!(feature = "debug") {
for k in 0..m {
pivotrow[k] = -1;
}
for k in 0..m {
pivotcol[k] = -1;
}
}
let mut lrank = rank;
for i in 0..m {
if lu.pinv[i] < 0 {
lu.pinv[i] = lrank as LUInt;
lrank += 1;
}
pivotrow[lu.pinv[i] as usize] = i as LUInt;
}
assert_eq!(lrank, m);
let mut lrank = rank;
for j in 0..m {
if lu.qinv[j] < 0 {
lu.qinv[j] = lrank as LUInt;
lrank += 1;
}
pivotcol[lu.qinv[j] as usize] = j as LUInt;
}
assert_eq!(lrank, m);
if cfg!(feature = "debug") {
for k in 0..m {
assert!(pivotrow[k] >= 0);
}
for k in 0..m {
assert!(pivotcol[k] >= 0);
}
}
for k in rank..m {
lu.col_pivot[pivotcol[k] as usize] = 1.0;
}
let mut put = lu.l_begin_p[rank as usize];
for k in rank..m {
l_index[put as usize] = -1;
put += 1;
lu.l_begin_p[k + 1] = put;
}
assert_eq!(lu.l_begin_p[m as usize], (l_nz + m) as LUInt);
for i in 0..m {
l_begin[i] = lu.l_begin_p[lu.pinv[i] as usize];
}
iwork1.fill(0); for get in 0..l_nz + m {
let i = l_index[get];
if i >= 0 {
iwork1[i as usize] += 1;
}
}
let mut put = (l_nz + m) as LUInt; for k in 0..m {
let i = pivotrow[k] as usize;
lt_begin_p[k] = put;
lt_begin[i] = put;
put += iwork1[i];
l_index[put as usize] = -1; put += 1;
iwork1[i] = lt_begin_p[k];
}
assert_eq!(put as usize, 2 * (l_nz + m));
for k in 0..m {
let ipivot = pivotrow[k];
let mut get = lu.l_begin_p[k] as usize;
while l_index[get] >= 0 {
let put = iwork1[l_index[get] as usize] as usize; iwork1[l_index[get] as usize] += 1;
l_index[put] = ipivot;
l_value[put] = l_value[get];
get += 1;
}
}
if cfg!(feature = "debug") {
for i in 0..m {
assert_eq!(l_index[iwork1[i] as usize], -1);
}
}
r_begin[0] = 2 * (l_nz + m) as LUInt;
file_empty(
m,
&mut lu.w_begin,
&mut lu.w_end,
&mut lu.w_flink,
&mut lu.w_blink,
w_mem as LUInt,
);
iwork1.fill(0); let mut put = 0;
if rank == m {
for k in 0..m {
let jpivot = pivotcol[k] as usize;
lu.w_begin[jpivot] = put;
let mut nz = 0;
for pos in lu.u_begin[k]..lu.u_begin[k + 1] {
let j = u_index[pos as usize];
w_index[put as usize] = j;
let put0 = put;
put += 1;
w_value[put0 as usize] = u_value[pos as usize];
iwork1[j as usize] += 1;
nz += 1;
}
lu.w_end[jpivot] = put;
put += (stretch * nz as f64) as LUInt + pad as LUInt;
list_move(jpivot, 0, &mut lu.w_flink, &mut lu.w_blink, m, None);
}
} else {
u_nz = 0; for k in 0..rank as usize {
let jpivot = pivotcol[k] as usize;
lu.w_begin[jpivot] = put;
let mut nz = 0;
for pos in lu.u_begin[k]..lu.u_begin[k + 1] {
let j = u_index[pos as usize];
if lu.qinv[j as usize] < rank as LUInt {
w_index[put as usize] = j;
let put0 = put;
put += 1;
w_value[put0 as usize] = u_value[pos as usize];
iwork1[j as usize] += 1;
nz += 1;
}
}
lu.w_end[jpivot] = put;
put += (stretch * nz as f64) as LUInt + pad as LUInt;
list_move(jpivot, 0, &mut lu.w_flink, &mut lu.w_blink, m, None);
u_nz += nz;
}
for k in rank..m {
let jpivot = pivotcol[k] as usize;
lu.w_begin[jpivot] = put;
lu.w_end[jpivot] = put;
put += pad as LUInt;
list_move(jpivot, 0, &mut lu.w_flink, &mut lu.w_blink, m, None);
}
}
assert!(put <= lu.w_end[m]);
lu.w_begin[m] = put;
u_index[0] = -1;
let mut put = 1;
for k in 0..m {
let j = pivotcol[k] as usize;
let i = pivotrow[k] as usize;
let nz = iwork1[j];
if nz == 0 {
lu.u_begin[i] = 0; } else {
lu.u_begin[i] = put;
put += nz;
u_index[put as usize] = -1; put += 1;
}
iwork1[j] = lu.u_begin[i];
}
lu.u_begin[m] = put;
for k in 0..m {
let jpivot = pivotcol[k] as usize;
let i = pivotrow[k];
for pos in lu.w_begin[jpivot]..lu.w_end[jpivot] {
let j = w_index[pos as usize] as usize;
let put = iwork1[j] as usize;
iwork1[j] += 1;
assert!(put >= 1);
u_index[put] = i;
u_value[put] = w_value[pos as usize];
}
}
if cfg!(feature = "debug") {
for j in 0..m {
assert_eq!(u_index[iwork1[j] as usize], -1);
}
}
for k in 0..m {
let i = pivotrow[k];
let j = pivotcol[k];
pmap!(lu)[j as usize] = i;
qmap!(lu)[i as usize] = j;
}
let mut max_pivot = 0.0;
let mut min_pivot = f64::INFINITY;
for i in 0..m {
lu.row_pivot[i] = lu.col_pivot[qmap![lu][i] as usize];
let pivot = lu.row_pivot[i].abs();
max_pivot = f64::max(pivot, max_pivot);
min_pivot = f64::min(pivot, min_pivot);
}
p![lu][..m].copy_from_slice(&pivotrow[..m]);
lu.min_pivot = min_pivot;
lu.max_pivot = max_pivot;
lu.pivotlen = m;
lu.l_nz = l_nz;
lu.u_nz = u_nz;
lu.r_nz = 0;
status
}