use crate::internal::{dordstat, OFF};
use crate::gplu::PivotPolicy;
use crate::Scalar;
pub fn lucopy<S: Scalar>(
pivot: &PivotPolicy,
pthresh: f64,
dthresh: f64,
nzcount: isize,
jcol1: usize,
_ncol: usize,
lastlu: &mut usize,
lu: &mut [S],
lurow: &mut [isize],
lcolst: &mut [usize],
ucolst: &mut [usize],
rperm: &mut [usize],
cperm: &[usize],
dense: &mut [S],
pattern: &[usize],
twork: &mut [f64],
) -> Result<isize, String> {
let jcol = jcol1 - 1;
let mut ujjptr: usize = 0;
if *pivot == PivotPolicy::NoPivoting || *pivot == PivotPolicy::NoDiagonalElement {
if ucolst[jcol + 1] - 1 < ucolst[jcol] {
return Err("zero length (U-I+L) column".to_string());
}
let mut nzcpy = ucolst[jcol] - 1;
for nzptr in ucolst[jcol] - 1..lcolst[jcol] - 1 {
let irow = lurow[nzptr] as usize - 1;
if pattern[irow] != 0 || irow == cperm[jcol] - 1 {
lurow[nzcpy] = irow as isize + 1;
lu[nzcpy] = dense[irow];
dense[irow] = S::zero();
nzcpy += 1;
} else {
dense[irow] = S::zero();
}
}
let lastu = nzcpy;
for nzptr in lcolst[jcol] - 1..ucolst[jcol + 1] - 1 {
let irow = lurow[nzptr] as usize - 1;
if pattern[irow] == 2 {
ujjptr = nzcpy + 1
}
if pattern[irow] != 0 || pattern[irow] == 2 {
lurow[nzcpy] = irow as isize + 1;
lu[nzcpy] = dense[irow];
dense[irow] = S::zero();
nzcpy += 1;
} else {
dense[irow] = S::zero();
}
}
lcolst[jcol] = lastu + 1;
ucolst[jcol + 1] = nzcpy + 1;
*lastlu = nzcpy;
if *pivot == PivotPolicy::NoDiagonalElement {
let zpivot = 0; return Ok(zpivot);
}
} else {
let udthreshabs: f64;
let ldthreshabs: f64;
let mut rnd: usize = 0;
if ucolst[jcol + 1] - 1 < lcolst[jcol] {
return Err("zero length L column".to_string());
}
if nzcount <= 0 {
let mut maxpivglb = -1.0;
for nzptr in ucolst[jcol] - 1..lcolst[jcol] - 1 {
let irow = lurow[nzptr] as usize;
let utemp = dense[irow - OFF].abs();
if utemp > maxpivglb {
maxpivglb = utemp;
}
}
udthreshabs = dthresh * maxpivglb;
maxpivglb = -1.0;
for nzptr in lcolst[jcol] - 1..ucolst[jcol + 1] - 1 {
let irow = lurow[nzptr] as usize;
let utemp = dense[irow - OFF].abs();
if utemp > maxpivglb {
maxpivglb = utemp;
}
}
ldthreshabs = dthresh * maxpivglb;
} else {
let mut i: usize = 0;
for nzptr in ucolst[jcol] - 1..lcolst[jcol] - 1 {
let irow = lurow[nzptr] as usize;
twork[i] = dense[irow - OFF].abs();
i += 1;
}
if (nzcount as usize) < i {
let mut kth: f64 = 0.0;
let mut info: isize = 0;
dordstat(
&mut rnd,
i,
i - (nzcount as usize) + 1,
twork,
&mut kth,
&mut info,
);
udthreshabs = kth;
} else {
udthreshabs = 0.0;
}
let mut i: usize = 0;
for nzptr in lcolst[jcol] - 1..ucolst[jcol + 1] - 1 {
let irow = lurow[nzptr] as usize;
twork[i] = dense[irow - OFF].abs();
i += 1;
}
if (nzcount as usize) < i {
let mut kth: f64 = 0.0;
let mut info: isize = 0;
dordstat(
&mut rnd,
i,
i - (nzcount as usize) + 1,
twork,
&mut kth,
&mut info,
);
ldthreshabs = kth;
} else {
ldthreshabs = 0.0;
}
}
let mut nzcpy = ucolst[jcol] - 1;
if lcolst[jcol] - 1 >= ucolst[jcol] {
for nzptr in ucolst[jcol] - 1..lcolst[jcol] - 1 {
let irow = lurow[nzptr] as usize - 1;
if pattern[irow] != 0 || dense[irow].abs() >= udthreshabs {
lurow[nzcpy] = irow as isize + 1;
lu[nzcpy] = dense[irow];
dense[irow] = S::zero();
nzcpy += 1;
} else {
dense[irow] = S::zero();
}
}
}
let lastu = nzcpy;
if ucolst[jcol + 1] - 1 < lcolst[jcol] {
return Err("zero length L column".to_string());
}
let mut diagptr: usize = 0;
let mut diagpiv: f64 = 0.0;
ujjptr = 0;
let mut maxpiv = -1.0;
let mut maxpivglb = -1.0;
for nzptr in lcolst[jcol] - 1..ucolst[jcol + 1] - 1 {
let irow = lurow[nzptr] as usize - 1;
let utemp = dense[irow].abs();
if pattern[irow] == 2 {
diagptr = irow + 1;
diagpiv = utemp;
}
if utemp > maxpiv {
ujjptr = irow + 1;
maxpiv = utemp;
}
if utemp > maxpivglb {
maxpivglb = utemp;
}
}
if diagptr != 0 && diagpiv >= (pthresh * maxpiv) {
ujjptr = diagptr
}
if diagptr == 0 && ujjptr == 0 {
print!("error: {}", ucolst[jcol + 1] - lcolst[jcol]);
}
diagptr = ujjptr;
ujjptr = 0;
for nzptr in lcolst[jcol] - 1..ucolst[jcol + 1] - 1 {
let irow = lurow[nzptr] as usize - 1;
let utemp = dense[irow].abs();
if pattern[irow] == 0 && irow != diagptr - 1 && utemp < ldthreshabs {
dense[irow] = S::zero();
} else {
if irow == diagptr - 1 {
ujjptr = nzcpy + 1;
}
lurow[nzcpy] = irow as isize + 1;
lu[nzcpy] = dense[irow];
dense[irow] = S::zero();
nzcpy += 1;
}
}
lcolst[jcol] = lastu + 1;
ucolst[jcol + 1] = nzcpy + 1;
*lastlu = nzcpy;
}
if ujjptr == 0 {
return Err(format!(
"ujjptr not set (1) {} {} {}",
ujjptr,
lcolst[jcol],
ucolst[jcol + 1] - 1
));
}
let pivrow = lurow[ujjptr - OFF];
let ujj = lu[ujjptr - OFF];
if ujj == S::zero() {
return Err(format!(
"numerically zero diagonal element at column {}",
jcol1
));
}
let dptr = lcolst[jcol];
lurow[ujjptr - OFF] = lurow[dptr - OFF];
lu[ujjptr - OFF] = lu[dptr - OFF];
lurow[dptr - OFF] = pivrow;
lu[dptr - OFF] = ujj;
lcolst[jcol] = dptr + 1;
rperm[pivrow as usize - OFF] = jcol1;
let nzst = lcolst[jcol];
let nzend = ucolst[jcol + 1] - 1;
if nzst > nzend {
let zpivot = pivrow;
return Ok(zpivot);
}
for nzptr in nzst..=nzend {
lu[nzptr - OFF] = lu[nzptr - OFF] / ujj;
}
let zpivot = pivrow;
return Ok(zpivot);
}