use crate::lu::lu::*;
use crate::LUInt;
use crate::Status;
use std::time::Instant;
pub(crate) fn singletons(
lu: &mut LU,
b_begin: &[usize],
b_end: &[usize],
b_i: &[usize],
b_x: &[f64],
) -> Status {
let m = lu.m;
let l_mem = lu.l_mem;
let u_mem = lu.u_mem;
let w_mem = lu.w_mem;
let abstol = lu.abstol;
let nzbias = lu.nzbias;
let pinv = &mut lu.pinv;
let qinv = &mut lu.qinv;
let l_begin_p = &mut lu.l_begin_p;
let u_begin = &mut lu.u_begin;
let col_pivot = &mut lu.col_pivot;
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 (iwork1, iwork2) = iwork1!(lu).split_at_mut(m as usize);
let b_tp = &mut lu.w_begin; let b_ti = &mut lu.w_index;
let b_tx = &mut lu.w_value;
let tic = Instant::now();
let mut b_nz: usize = 0;
let mut ok = 1;
let mut j = 0;
while j < m && ok != 0 {
if b_end[j] < b_begin[j] {
ok = 0;
} else {
b_nz += (b_end[j] - b_begin[j]) as usize;
}
j += 1;
}
if ok == 0 {
return Status::ErrorInvalidArgument;
}
let mut ok = 1;
if l_mem < b_nz {
lu.addmem_l = b_nz - l_mem;
ok = 0;
}
if u_mem < b_nz {
lu.addmem_u = b_nz - u_mem;
ok = 0;
}
if w_mem < b_nz {
lu.addmem_w = b_nz - w_mem;
ok = 0;
}
if ok == 0 {
return Status::Reallocate;
}
iwork1.fill(0); let mut ok = 1;
let mut j = 0;
while j < m && ok != 0 {
let mut pos = b_begin[j];
while pos < b_end[j] && ok != 0 {
let i = b_i[pos as usize];
if i >= m {
ok = 0;
} else {
iwork1[i] += 1;
}
pos += 1;
}
j += 1;
}
if ok == 0 {
return Status::ErrorInvalidArgument;
}
let mut put: usize = 0;
for i in 0..m as usize {
b_tp[i] = put as LUInt;
put += iwork1[i] as usize;
iwork1[i] = b_tp[i];
}
b_tp[m as usize] = put as LUInt;
assert_eq!(put, b_nz);
let mut ok = 1;
for j in 0..m {
for pos in b_begin[j] as usize..b_end[j] as usize {
let i = b_i[pos] as usize;
put = iwork1[i] as usize;
iwork1[i] += 1;
b_ti[put] = j as LUInt;
b_tx[put] = b_x[pos];
if put > b_tp[i] as usize && b_ti[put - 1] as usize == j {
ok = 0;
}
}
}
if ok == 0 {
return Status::ErrorInvalidArgument;
}
for i in 0..m {
pinv[i as usize] = -1;
}
for j in 0..m {
qinv[j as usize] = -1;
}
let rank = if nzbias.is_some() {
l_begin_p[0] = 0;
u_begin[0] = 0;
let rank = 0;
let rank = singleton_cols(
m, b_begin, b_end, b_i, b_x, b_tp, b_ti, b_tx, u_begin, u_index, u_value, l_begin_p,
l_index, l_value, col_pivot, pinv, qinv, iwork1, iwork2, rank, abstol,
);
let rank = singleton_rows(
m, b_begin, b_end, b_i, b_x, b_tp, b_ti, b_tx, u_begin, u_index, u_value, l_begin_p,
l_index, l_value, col_pivot, pinv, qinv, iwork1, iwork2, rank, abstol,
);
rank
} else {
l_begin_p[0] = 0;
u_begin[0] = 0;
let rank = 0;
let rank = singleton_rows(
m, b_begin, b_end, b_i, b_x, b_tp, b_ti, b_tx, u_begin, u_index, u_value, l_begin_p,
l_index, l_value, col_pivot, pinv, qinv, iwork1, iwork2, rank, abstol,
);
let rank = singleton_cols(
m, b_begin, b_end, b_i, b_x, b_tp, b_ti, b_tx, u_begin, u_index, u_value, l_begin_p,
l_index, l_value, col_pivot, pinv, qinv, iwork1, iwork2, rank, abstol,
);
rank
};
for i in 0..m as usize {
if pinv[i] < 0 {
pinv[i] = -1;
}
}
for j in 0..m as usize {
if qinv[j] < 0 {
qinv[j] = -1;
}
}
lu.matrix_nz = b_nz;
lu.rank = rank;
lu.time_singletons = tic.elapsed().as_secs_f64();
Status::OK
}
pub(crate) fn singleton_cols(
m: usize,
b_begin: &[usize], b_end: &[usize],
b_i: &[usize],
_b_x: &[f64],
b_tp: &[LUInt],
b_ti: &[LUInt],
b_tx: &[f64],
u_p: &mut [LUInt],
u_i: &mut [LUInt],
u_x: &mut [f64],
l_p: &mut [LUInt],
l_i: &mut [LUInt],
_l_x: &mut [f64],
col_pivot: &mut [f64],
pinv: &mut [LUInt],
qinv: &mut [LUInt],
iset: &mut [LUInt], queue: &mut [LUInt], mut rank: usize,
abstol: f64,
) -> usize {
let mut rk = rank;
let mut tail = 0;
for j in 0..m {
if qinv[j] < 0 {
let nz = b_end[j] - b_begin[j];
let mut i = 0;
for pos in b_begin[j]..b_end[j] {
i ^= b_i[pos as usize]; }
iset[j] = i as LUInt;
qinv[j] = -(nz as LUInt) - 1; if nz == 1 {
queue[tail] = j as LUInt;
tail += 1;
}
}
}
let mut put = u_p[rank];
for front in 0..tail {
let j = queue[front];
assert!(qinv[j as usize] == -2 || qinv[j as usize] == -1);
if qinv[j as usize] == -1 {
continue; }
let i = iset[j as usize] as usize;
assert!( i < m);
assert!(pinv[i as usize] < 0);
let end = b_tp[(i + 1) as usize];
let mut pos = b_tp[i as usize];
while b_ti[pos as usize] != j {
assert!(pos < end - 1);
pos += 1;
}
let piv = b_tx[pos as usize];
if piv == 0.0 || piv.abs() < abstol {
continue; }
qinv[j as usize] = rank as LUInt;
pinv[i as usize] = rank as LUInt;
for pos in b_tp[i as usize]..end {
let j2 = b_ti[pos as usize];
if qinv[j2 as usize] < 0 {
u_i[put as usize] = j2;
u_x[put as usize] = b_tx[pos as usize];
put += 1;
iset[j2 as usize] ^= i as LUInt;
qinv[j2 as usize] += 1;
if qinv[j2 as usize] == -2 {
queue[tail as usize] = j2; tail += 1;
}
}
}
u_p[rank + 1] = put;
col_pivot[j as usize] = piv;
rank += 1;
}
let mut pos = l_p[rk as usize];
while rk < rank {
l_i[pos as usize] = -1;
pos += 1;
l_p[(rk + 1) as usize] = pos;
rk += 1;
}
rank
}
fn singleton_rows(
m: usize,
b_begin: &[usize], b_end: &[usize],
b_i: &[usize],
b_x: &[f64],
b_tp: &[LUInt], b_ti: &[LUInt],
_b_tx: &[f64],
u_p: &mut [LUInt],
_u_i: &mut [LUInt],
_u_x: &mut [f64],
l_p: &mut [LUInt],
l_i: &mut [LUInt],
l_x: &mut [f64],
col_pivot: &mut [f64],
pinv: &mut [LUInt],
qinv: &mut [LUInt],
iset: &mut [LUInt], queue: &mut [LUInt], mut rank: usize,
abstol: f64,
) -> usize {
let mut rk = rank;
let mut tail = 0;
for i in 0..m {
if pinv[i] < 0 {
let nz = b_tp[i + 1] - b_tp[i];
let mut j = 0;
for pos in b_tp[i]..b_tp[i + 1] {
j ^= b_ti[pos as usize]; }
iset[i] = j;
pinv[i] = -nz - 1;
if nz == 1 {
queue[tail] = i as LUInt;
tail += 1;
}
}
}
let mut put = l_p[rank] as usize;
for front in 0..tail {
let i = queue[front] as usize;
assert!(pinv[i] == -2 || pinv[i] == -1);
if pinv[i] == -1 {
continue; }
let j = iset[i] as usize;
assert!( j < m);
assert!(qinv[j] < 0);
let end = b_end[j] as usize;
let mut pos = b_begin[j] as usize;
while b_i[pos] != i {
assert!(pos < end - 1);
pos += 1;
}
let piv = b_x[pos];
if piv == 0.0 || piv.abs() < abstol {
continue; }
qinv[j] = rank as LUInt;
pinv[i] = rank as LUInt;
for pos in b_begin[j] as usize..end {
let i2 = b_i[pos] as usize;
if pinv[i2] < 0 {
l_i[put] = i2 as LUInt;
l_x[put] = b_x[pos] / piv;
put += 1;
iset[i2] ^= j as LUInt;
pinv[i2] += 1;
if pinv[i2] == -2 {
queue[tail] = i2 as LUInt; tail += 1;
}
}
}
l_i[put] = -1; put += 1;
l_p[rank + 1] = put as LUInt;
col_pivot[j] = piv;
rank += 1;
}
let pos = u_p[rk as usize];
while rk < rank {
u_p[(rk + 1) as usize] = pos;
rk += 1;
}
rank
}