use crate::lu::list::list_move;
use crate::lu::LU;
use crate::{IntLeast64, LUInt, Status};
use std::time::Instant;
pub(crate) fn markowitz(lu: &mut LU) -> Status {
let m = lu.m;
let w_begin = &lu.w_begin;
let w_end = &lu.w_end;
let w_index = &lu.w_index;
let w_value = &lu.w_value;
let colcount_flink = &lu.colcount_flink;
let rowcount_flink = &mut lu.rowcount_flink;
let rowcount_blink = &mut lu.rowcount_blink;
let colmax = &lu.col_pivot;
let abstol = lu.abstol;
let reltol = lu.reltol;
let maxsearch = lu.maxsearch;
let search_rows = lu.search_rows;
let nz_start = if search_rows != 0 {
usize::min(lu.min_colnz, lu.min_rownz)
} else {
lu.min_colnz
};
let m64 = m as IntLeast64;
let tic = Instant::now();
let mut pivot_row: Option<usize> = None; let mut pivot_col: Option<usize> = None; let mut mc64: IntLeast64 = m64 * m64; let mut nsearch = 0; let mut min_colnz: Option<usize> = None; let mut min_rownz: Option<usize> = None; assert!(nz_start >= 1);
if colcount_flink[m] != m as LUInt {
pivot_col = Some(colcount_flink[m] as usize);
assert!(pivot_col.is_some() && pivot_col.unwrap() < m);
assert_eq!(w_end[pivot_col.unwrap()], w_begin[pivot_col.unwrap()]);
return done(lu, pivot_row, pivot_col, nsearch, min_colnz, min_rownz, tic);
}
for nz in nz_start..=m {
let mut j = colcount_flink[(m + nz) as usize];
while j < m as LUInt {
if min_colnz.is_none() {
min_colnz = Some(nz);
}
assert_eq!(w_end[j as usize] - w_begin[j as usize], nz as LUInt);
let cmx = colmax[j as usize];
assert!(cmx >= 0.0);
if cmx == 0.0 || cmx < abstol {
continue;
}
let tol = f64::max(abstol, reltol * cmx);
for pos in w_begin[j as usize]..w_end[j as usize] {
let x = w_value[pos as usize].abs();
if x == 0.0 || x < tol {
continue;
}
let i = w_index[pos as usize] as usize;
assert!( i < m);
let nz1: IntLeast64 = nz as IntLeast64;
let nz2: IntLeast64 = w_end[m + i] - w_begin[m + i];
assert!(nz2 >= 1);
let mc: IntLeast64 = (nz1 - 1) * (nz2 - 1);
if mc < mc64 {
mc64 = mc;
pivot_row = Some(i);
pivot_col = Some(j as usize);
if search_rows != 0 && mc64 <= (nz1 - 1) * (nz1 - 1) {
return done(lu, pivot_row, pivot_col, nsearch, min_colnz, min_rownz, tic);
}
}
}
assert!(mc64 < m64 * m64);
nsearch += 1;
if nsearch >= maxsearch {
return done(lu, pivot_row, pivot_col, nsearch, min_colnz, min_rownz, tic);
}
j = colcount_flink[j as usize];
}
assert_eq!(j, (m + nz) as LUInt);
if search_rows == 0 {
continue;
}
let mut i = rowcount_flink[(m + nz) as usize];
while i < m as LUInt {
if min_rownz.is_none() {
min_rownz = Some(nz);
}
let inext = rowcount_flink[i as usize];
assert_eq!(
w_end[((m as LUInt) + i) as usize] - w_begin[((m as LUInt) + i) as usize],
nz as LUInt
);
let mut cheap = 0; let mut found = 0; for pos in w_begin[((m as LUInt) + i) as usize]..w_end[((m as LUInt) + i) as usize] {
let j = w_index[pos as usize] as usize;
assert!( j < m);
let nz1: IntLeast64 = nz as IntLeast64;
let nz2: IntLeast64 = w_end[j] - w_begin[j];
assert!(nz2 >= 1);
let mc: IntLeast64 = (nz1 - 1) * (nz2 - 1);
if mc >= mc64 {
continue;
}
cheap = 1;
let cmx = colmax[j];
assert!(cmx >= 0.0);
if cmx == 0.0 || cmx < abstol {
continue;
}
let mut where_ = w_begin[j];
while w_index[where_ as usize] != i {
assert!(where_ < w_end[j] - 1);
where_ += 1;
}
let x = w_value[where_ as usize].abs();
if x >= abstol && x >= reltol * cmx {
found = 1;
mc64 = mc;
pivot_row = Some(i as usize);
pivot_col = Some(j);
if mc64 <= nz1 * (nz1 - 1) {
return done(lu, pivot_row, pivot_col, nsearch, min_colnz, min_rownz, tic);
}
}
}
if cheap != 0 && found == 0 {
list_move(i as usize, m + 1, rowcount_flink, rowcount_blink, m, None);
} else {
assert!(mc64 < m64 * m64);
nsearch += 1;
if nsearch >= maxsearch {
return done(lu, pivot_row, pivot_col, nsearch, min_colnz, min_rownz, tic);
}
}
i = inext;
}
assert_eq!(i, (m + nz) as LUInt);
}
done(lu, pivot_row, pivot_col, nsearch, min_colnz, min_rownz, tic)
}
fn done(
lu: &mut LU,
pivot_row: Option<usize>,
pivot_col: Option<usize>,
nsearch: usize,
min_colnz: Option<usize>,
min_rownz: Option<usize>,
tic: Instant,
) -> Status {
lu.pivot_row = pivot_row;
lu.pivot_col = pivot_col;
lu.nsearch_pivot += nsearch;
if let Some(min_colnz) = min_colnz {
lu.min_colnz = min_colnz;
}
if let Some(min_rownz) = min_rownz {
lu.min_rownz = min_rownz;
}
lu.time_search_pivot += tic.elapsed().as_secs_f64();
Status::OK
}