use super::miniblas::{ddot, dscal, dcopy};
use super::linpack::{dtrsl, dpofa, LinpackError};
use super::debug::{print_fvector};
use log::{info, debug, warn, trace};
const C_1: i32 = 1;
const C_11: i32 = 11;
pub fn active(
n: usize,
l: &[f64],
u: &[f64],
nbd: &[i32],
x: &mut [f64],
iwhere: &mut [i32],
prjctd: &mut bool,
cnstnd: &mut bool,
boxed: &mut bool,
) {
let mut nbdd = 0;
*prjctd = false;
*cnstnd = false;
*boxed = true;
for i in 0..n {
if nbd[i] > 0 {
if nbd[i] <= 2 && x[i] <= l[i] {
if x[i] < l[i] {
*prjctd = true;
x[i] = l[i];
}
nbdd += 1;
} else if nbd[i] >= 2 && x[i] >= u[i] {
if x[i] > u[i] {
*prjctd = true;
x[i] = u[i];
}
nbdd += 1;
}
}
}
for i in 0..n {
if nbd[i] != 2 {
*boxed = false;
}
if nbd[i] == 0 {
iwhere[i] = -1;
} else {
*cnstnd = true;
if nbd[i] == 2 && u[i] - l[i] <= 0.0 {
iwhere[i] = 3;
} else {
iwhere[i] = 0;
}
}
}
if *prjctd {
info!("The initial X is infeasible. Restart with its projection");
}
if !*cnstnd {
info!("This problem is unconstrained");
}
info!("At X0, {} variables are exactly at the bounds", nbdd);
}
pub fn bmv(
m: usize,
sy: &[f64],
wt: &[f64],
col: usize,
v: &[f64],
p: &mut [f64],
) -> Result<(), i32> {
if col == 0 {
return Ok(());
}
p[col] = v[col];
for i in 2..=col {
let i2 = col + i;
let mut sum = 0.0;
for k in 1..i {
sum += sy[(i-1) + (k-1) * m] * v[k-1] / sy[(k-1) + (k-1) * m];
}
p[i2-1] = v[i2-1] + sum;
}
let mut p_col_plus = vec![0.0; col];
for i in 0..col {
p_col_plus[i] = p[col + i];
}
let mut wt_copy = vec![0.0; wt.len()];
wt_copy.copy_from_slice(wt);
match dtrsl(
&mut wt_copy,
m,
col,
&mut p_col_plus,
C_11 ) {
Ok(_) => {
for i in 0..col {
p[col + i] = p_col_plus[i];
}
},
Err(_) => return Err(1),
}
for i in 1..=col {
p[i-1] = v[i-1] / sy[(i-1) + (i-1) * m].sqrt();
}
let mut p_col_plus = vec![0.0; col];
for i in 0..col {
p_col_plus[i] = p[col + i];
}
match dtrsl(
&mut wt_copy,
m,
col,
&mut p_col_plus,
C_1 ) {
Ok(_) => {
for i in 0..col {
p[col + i] = p_col_plus[i];
}
},
Err(_) => return Err(1),
}
for i in 1..=col {
p[i-1] = -p[i-1] / sy[(i-1) + (i-1) * m].sqrt();
}
for i in 1..=col {
let mut sum = 0.0;
for k in (i+1)..=col {
sum += sy[(k-1) + (i-1) * m] * p[col + k - 1] / sy[(i-1) + (i-1) * m];
}
p[i-1] += sum;
}
Ok(())
}
fn idx(idx0: usize) -> usize {
if idx0 > 0 {
idx0 - 1
}
else {
0
}
}
fn initialize_cauchy(
n: usize,
x: &[f64],
l: &[f64],
u: &[f64],
nbd: &[i32],
g: &[f64],
iorder: &mut [i32],
iwhere: &mut [i32],
t: &mut [f64],
d: &mut [f64],
m: usize,
wy: &[f64],
ws: &[f64],
col: usize,
head: usize,
p: &mut [f64]
) -> (bool, usize, usize, usize, f64, f64) {
let mut bnded = true;
let mut nfree = n + 1;
let mut nbreak = 0;
let mut ibkmin = 0;
let mut bkmin = 0.0;
let col2 = col * 2;
let mut f1 = 0.0;
let mut tl: f64 = 0.0;
let mut tu: f64 = 0.0;
for i in 0..col2 {
p[i] = 0.0;
}
for i in 0..n {
let neggi = -g[i];
if iwhere[i] != 3 && iwhere[i] != -1 {
tl = 0.0;
tu = 0.0;
if nbd[i] <= 2 {
tl = x[i] - l[i];
}
if nbd[i] >= 2 {
tu = u[i] - x[i];
}
let xlower = nbd[i] <= 2 && tl <= 0.0;
let xupper = nbd[i] >= 2 && tu <= 0.0;
iwhere[i] = 0;
if xlower {
if neggi <= 0.0 {
iwhere[i] = 1;
}
} else if xupper {
if neggi >= 0.0 {
iwhere[i] = 2;
}
} else if neggi.abs() <= 0.0 {
iwhere[i] = -3;
}
} else {
trace!(" Variable {} is fixed (iwhere[{}] = {})", i, i, iwhere[i]);
}
let mut pointr = head;
if iwhere[i] != 0 && iwhere[i] != -1 {
d[i] = 0.0;
} else {
d[i] = neggi;
f1 -= neggi * neggi;
for j in 0..col {
p[j] += wy[i + idx(pointr) * n] * neggi;
p[col + j] += ws[i + idx(pointr) * n] * neggi;
pointr = pointr % m + 1;
}
if nbd[i] <= 2 && nbd[i] != 0 && neggi < 0.0 {
nbreak += 1;
iorder[idx(nbreak)] = i as i32 + 1; t[idx(nbreak)] = tl / -neggi;
if nbreak == 1 || t[idx(nbreak)] < bkmin {
bkmin = t[idx(nbreak)];
ibkmin = nbreak;
}
} else if nbd[i] >= 2 && neggi > 0.0 {
nbreak += 1;
iorder[idx(nbreak)] = i as i32 + 1; t[idx(nbreak)] = tu / neggi;
if nbreak == 1 || t[idx(nbreak)] < bkmin {
bkmin = t[idx(nbreak)];
ibkmin = nbreak;
}
} else {
nfree -= 1;
iorder[idx(nfree)] = i as i32 + 1;
if neggi.abs() > 0.0 {
bnded = false;
}
}
}
}
(bnded, nfree, nbreak, ibkmin, bkmin, f1)
}
fn heap_sort(t: &mut [f64], iorder: &mut [i32], n: usize, iheap: i32) {
if iheap == 0 {
for k in 1..=n {
let ddum = t[idx(k)];
let indxin = iorder[idx(k)];
let mut i = k;
while i > 1 {
let j = i / 2;
if !(ddum < t[idx(j)]) {
break;
}
t[idx(i)] = t[idx(j)];
iorder[idx(i)] = iorder[idx(j)];
i = j;
}
t[idx(i)] = ddum;
iorder[idx(i)] = indxin;
}
}
if n > 0 {
let out = t[0];
let indxou = iorder[0];
let ddum = t[idx(n)];
let indxin = iorder[idx(n)];
let mut i = 1;
loop {
let mut j = i + i;
if j > n - 1 {
break;
}
if j < n - 1 && t[idx(j + 1)] < t[idx(j)] {
j += 1;
}
if !(t[idx(j)] < ddum) {
break;
}
t[idx(i)] = t[idx(j)];
iorder[idx(i)] = iorder[idx(j)];
i = j;
}
t[idx(i)] = ddum;
iorder[idx(i)] = indxin;
t[idx(n)] = out;
iorder[idx(n)] = indxou;
}
}
pub fn cauchy(
n: usize,
x: &[f64],
l: &[f64],
u: &[f64],
nbd: &[i32],
g: &[f64],
iorder: &mut [i32],
iwhere: &mut [i32],
t: &mut [f64],
d: &mut [f64],
xcp: &mut [f64],
m: usize,
wy: &[f64],
ws: &[f64],
sy: &[f64],
wt: &[f64],
theta: f64,
col: usize,
head: usize,
p: &mut [f64],
c: &mut [f64],
wbp: &mut [f64],
v: &mut [f64],
nseg: &mut i32,
sbgnrm: f64,
epsmch: f64
) -> Result<(), i32> {
let col2 = 2 * col;
if sbgnrm <= 0.0 {
info!("Subnorm = 0. GCP = X.");
xcp.copy_from_slice(x);
return Ok(());
}
let (bnded, nfree, nbreak, ibkmin, bkmin, mut f1) = initialize_cauchy(
n, x, l, u, nbd, g, iorder, iwhere, t, d, m, wy, ws, col, head, p
);
if theta != 1.0 {
dscal(col as i32, theta, &mut p[col..], 1);
}
xcp.copy_from_slice(x);
if nbreak == 0 && nfree == n + 1 {
info!("No breakpoints and all variables are fixed. Returning with xcp = x.");
return Ok(());
}
for j in 0..col2 {
c[j] = 0.0;
}
let mut f2 = -theta * f1;
let f2_org = f2;
if col > 0 {
match bmv(m, sy, wt, col, p, v) {
Ok(_) => {
log::trace!("bmv successful");
},
Err(e) => {
log::warn!("Error during bmv: {:?}", e);
},
}
f2 -= ddot(col2 as i32, v, 1, p, 1);
}
let mut dtm = -f1 / f2; let mut tsum = 0.0; *nseg = 1;
if nbreak == 0 {
info!("No breakpoints. GCP found in first segment.");
debug!("Piece {} --f1={}, f2={} at start point", *nseg, f1, f2);
debug!("Distance to the stationary point = {}", dtm);
if dtm <= 0.0 {
dtm = 0.0;
}
for i in 0..n {
xcp[i] += tsum * d[i];
}
}
else {
let mut nleft = nbreak;
let mut iter = 1;
let mut tj = 0.0;
loop {
let tj0 = tj;
let mut ibp = 0;
if iter == 1 {
tj = bkmin;
ibp = iorder[idx(ibkmin)] as usize - 1; }
else {
if iter == 2 && ibkmin != nbreak {
t[idx(ibkmin)] = t[idx(nbreak)];
iorder[idx(ibkmin)] = iorder[idx(nbreak)];
}
heap_sort(t, iorder, nleft, iter - 2);
tj = t[idx(nleft)];
ibp = iorder[idx(nleft)] as usize - 1; }
let dt = tj - tj0;
if dt != 0.0 {
debug!("Piece {} --f1={}, f2={} at start point", *nseg, f1, f2);
debug!("Distance to the next break point = {}", dt);
debug!("Distance to the stationary point = {}", dtm);
}
if dtm < dt {
debug!("\nGCP found in this segment. Piece {} --f1, f2 at start point {} {}",
nseg, f1, f2);
debug!("Distance to the stationary point = {}", dtm);
if dtm <= 0.0 {
dtm = 0.0;
}
tsum += dtm;
for i in 0..n {
xcp[i] += tsum * d[i];
}
break;
}
tsum += dt;
nleft -= 1;
iter += 1;
let dibp = d[ibp];
d[ibp] = 0.0;
let mut zibp = 0.0;
if dibp > 0.0 {
zibp = u[ibp] - x[ibp];
xcp[ibp] = u[ibp];
iwhere[ibp] = 2;
}
else {
zibp = l[ibp] - x[ibp];
xcp[ibp] = l[ibp];
iwhere[ibp] = 1;
}
if nleft == 0 && nbreak == n {
dtm = dt;
tsum += dtm;
for i in 0..n {
xcp[i] += tsum * d[i];
}
break;
}
*nseg += 1;
let dibp2 = dibp * dibp;
f1 = f1 + dt * f2 + dibp2 - theta * dibp * zibp;
f2 -= theta * dibp2;
if col > 0 {
for i in 0..col2 {
c[i] += dt * p[i];
}
let mut j_pointr = head;
for j in 0..col {
wbp[j] = wy[ibp + idx(j_pointr) * n];
wbp[col + j] = theta * ws[ibp + idx(j_pointr) * n];
j_pointr = j_pointr % m + 1;
}
let result = bmv(m, sy, wt, col, wbp, v);
if let Err(_) = result {
return Ok(());
}
let wmc = ddot(col2 as i32, c, 1, v, 1);
let wmp = ddot(col2 as i32, p, 1, v, 1);
let wmw = ddot(col2 as i32, wbp, 1, v, 1);
for i in 0..col2 {
p[i] -= dibp * wbp[i];
}
f1 += dibp * wmc;
f2 = f2 + dibp * 2.0 * wmp - dibp2 * wmw;
}
f2 = f64::max(epsmch * f2_org, f2);
if nleft > 0 {
dtm = -f1 / f2;
}
else {
if bnded {
f1 = 0.0;
f2 = 0.0;
dtm = 0.0;
} else {
dtm = -f1 / f2;
}
info!("GCP found in final segment ({})", *nseg);
debug!("Piece {} --f1={}, f2={} at start point", *nseg, f1, f2);
debug!("Distance to the stationary point = {}", dtm);
if dtm <= 0.0 {
dtm = 0.0;
}
tsum += dtm;
for i in 0..n {
xcp[i] += tsum * d[i];
}
break;
}
}
}
if col > 0 {
for i in 0..col2 {
c[i] += dtm * p[i];
}
}
print_fvector(xcp, n, "Cauchy X = ");
Ok(())
}
pub fn cmprlb(
n: usize,
m: usize,
x: &[f64],
g: &[f64],
ws: &[f64],
wy: &[f64],
sy: &[f64],
wt: &[f64],
z: &[f64],
r: &mut [f64],
wa: &mut [f64],
index: &[i32],
theta: f64,
col: usize,
head: usize,
nfree: usize,
cnstnd: bool,
) -> Result<(), i32> {
if !cnstnd && col > 0 {
for i in 0..n {
r[i] = -g[i];
}
return Ok(());
}
for i in 0..nfree {
let k = index[i] as usize - 1; r[i] = -theta * (z[k] - x[k]) - g[k];
}
if col == 0 {
return Ok(());
}
let mut v = vec![0.0; 2 * col];
for i in 0..2*col {
v[i] = wa[2 * m + i];
}
let mut p = vec![0.0; 2 * col];
bmv(m, sy, wt, col, &v, &mut p)?;
for i in 0..2*col {
wa[i] = p[i];
}
let mut pointr = head;
for j in 1..=col {
let a1 = wa[j-1];
let a2 = theta * wa[col+j-1];
for i in 0..nfree {
let k = index[i] as usize - 1; r[i] += wy[k + (pointr-1) * n] * a1 + ws[k + (pointr-1) * n] * a2;
}
pointr = pointr % m + 1;
}
Ok(())
}
pub fn formk(
n: usize,
nsub: usize,
ind: &[i32],
nenter: usize,
ileave: usize,
indx2: &[i32],
iupdat: usize,
updatd: bool,
wn: &mut [f64],
wn1: &mut [f64],
m: usize,
ws: &[f64],
wy: &[f64],
sy: &[f64],
theta: f64,
col: usize,
head: usize,
) -> Result<(), i32> {
let wn1_dim: usize = 2 * m;
let wn_dim: usize = 2 * m;
if updatd {
if iupdat > m {
let i__1 = m - 1;
for jy in 0..i__1 {
let js = m + jy;
let i__2 = m - jy - 1; let src_offset = ((jy + 1) + (jy + 1) * wn1_dim) as usize; let dst_offset = (jy + jy * wn1_dim) as usize; let slice_len = i__2 as usize;
let src_slice_upper = wn1[src_offset.. src_offset + slice_len].to_vec();
dcopy(i__2 as i32, &src_slice_upper, 1, &mut wn1[dst_offset..dst_offset + slice_len], 1);
let i__2 = m - jy - 1; let src_offset = ((js + 1) + (js + 1) * wn1_dim) as usize; let dst_offset = (js + js * wn1_dim) as usize; let slice_len = i__2 as usize;
let src_slice_lower = wn1[src_offset.. src_offset + slice_len].to_vec();
dcopy(i__2 as i32, &src_slice_lower, 1, &mut wn1[dst_offset..dst_offset + slice_len], 1);
let i__2 = m - 1;
let src_offset = (m + 1 + (jy + 1) * wn1_dim) as usize; let dst_offset = (m + jy * wn1_dim) as usize; let slice_len = i__2 as usize;
let src_slice_rect = wn1[src_offset.. src_offset + slice_len].to_vec();
dcopy(i__2 as i32, &src_slice_rect, 1, &mut wn1[dst_offset..dst_offset + slice_len], 1);
}
}
let pbegin = 0;
let pend = nsub - 1;
let dbegin = nsub;
let dend = n - 1;
let iy = col - 1;
let is = m + col - 1;
let mut ipntr = head + col - 2;
if ipntr >= m {
ipntr -= m;
}
let mut jpntr = head - 1;
for jy in 0..col {
let js = m + jy;
let mut temp1 = 0.0; let mut temp2 = 0.0; let mut temp3 = 0.0;
for k in pbegin..=pend {
let k1 = ind[k] as usize - 1;
let wy_ipntr_k1 = wy[k1 + ipntr * n];
let wy_jpntr_k1 = wy[k1 + jpntr * n];
temp1 += wy_ipntr_k1 * wy_jpntr_k1;
}
for k in dbegin..=dend {
let k1 = ind[k] as usize - 1;
let ws_ipntr_k1 = ws[k1 + ipntr * n];
let ws_jpntr_k1 = ws[k1 + jpntr * n];
let wy_jpntr_k1 = wy[k1 + jpntr * n];
temp2 += ws_ipntr_k1 * ws_jpntr_k1;
temp3 += ws_ipntr_k1 * wy_jpntr_k1;
}
wn1[iy + jy * wn1_dim] = temp1;
wn1[is + js * wn1_dim] = temp2;
wn1[is + jy * wn1_dim] = temp3;
jpntr = (jpntr + 1) % m;
}
let jy = col - 1;
let mut jpntr = head + col - 2;
if jpntr >= m {
jpntr -= m;
}
let mut ipntr = head - 1;
for i in 0..col {
let is = m + i;
let mut temp3 = 0.0;
for k in pbegin..=pend {
let k1 = ind[k] as usize - 1;
let ws_ipntr_k1 = ws[k1 + ipntr * n];
let wy_jpntr_k1 = wy[k1 + jpntr * n];
temp3 += ws_ipntr_k1 * wy_jpntr_k1;
}
ipntr = (ipntr + 1) % m;
wn1[is + jy * wn1_dim] = temp3;
}
}
let upcl = if updatd { col - 1 } else { col };
let mut ipntr = head - 1;
for iy in 0..upcl {
let is = m + iy;
let mut jpntr = head - 1;
for jy in 0..=iy {
let js = m + jy;
let mut temp1 = 0.0; let mut temp2 = 0.0; let mut temp3 = 0.0; let mut temp4 = 0.0;
for k in 0..nenter {
let k1 = indx2[k] as usize - 1;
let wy_ipntr_k1 = wy[k1 + ipntr * n];
let wy_jpntr_k1 = wy[k1 + jpntr * n];
let ws_ipntr_k1 = ws[k1 + ipntr * n];
let ws_jpntr_k1 = ws[k1 + jpntr * n];
temp1 += wy_ipntr_k1 * wy_jpntr_k1;
temp2 += ws_ipntr_k1 * ws_jpntr_k1;
}
for k in (ileave - 1)..n {
let k1 = indx2[k] as usize - 1;
let wy_ipntr_k1 = wy[k1 + ipntr * n];
let wy_jpntr_k1 = wy[k1 + jpntr * n];
let ws_ipntr_k1 = ws[k1 + ipntr * n];
let ws_jpntr_k1 = ws[k1 + jpntr * n];
temp3 += wy_ipntr_k1 * wy_jpntr_k1;
temp4 += ws_ipntr_k1 * ws_jpntr_k1;
}
wn1[iy + jy * wn1_dim] += temp1 - temp3;
wn1[is + js * wn1_dim] += -temp2 + temp4;
jpntr = (jpntr + 1) % m;
}
ipntr = (ipntr + 1) % m;
}
let mut ipntr = head - 1;
for is in (m)..(m + upcl) {
let mut jpntr = head - 1;
for jy in 0..upcl {
let mut temp1 = 0.0; let mut temp3 = 0.0;
for k in 0..nenter {
let k1 = indx2[k] as usize - 1;
let ws_ipntr_k1 = ws[k1 + ipntr * n];
let wy_jpntr_k1 = wy[k1 + jpntr * n];
temp1 += ws_ipntr_k1 * wy_jpntr_k1;
}
for k in (ileave - 1)..n {
let k1 = indx2[k] as usize - 1;
let ws_ipntr_k1 = ws[k1 + ipntr * n];
let wy_jpntr_k1 = wy[k1 + jpntr * n];
temp3 += ws_ipntr_k1 * wy_jpntr_k1;
}
if is <= jy + m {
wn1[is + jy * wn1_dim] += temp1 - temp3;
} else {
wn1[is + jy * wn1_dim] += -temp1 + temp3;
}
jpntr = (jpntr + 1) % m;
}
ipntr = (ipntr + 1) % m;
}
for iy in 0..col {
let is = col + iy;
let is1 = m + iy;
for jy in 0..=iy {
let js = col + jy;
let js1 = m + jy;
wn[jy + iy * wn_dim] = wn1[iy + jy * wn_dim] / theta;
wn[js + is * wn_dim] = wn1[is1 + js1 * wn_dim] * theta;
}
for jy in 0..(iy) {
wn[jy + is * wn_dim] = -wn1[is1 + jy * wn_dim];
}
for jy in iy..col {
wn[jy + is * wn_dim] = wn1[is1 + jy * wn_dim];
}
wn[iy + iy * wn_dim] += sy[iy + iy * m];
}
match dpofa(wn, 2 * m, col) {
Ok(_) => {
trace!("Upper left block Cholesky factorization successful");
},
Err(e) => {
warn!("Upper left block Cholesky factorization failed with error: {:?}", e);
return Err(-1); },
}
let col2 = col << 1;
for js in (col)..col2 {
let mut wn_copy = vec![0.0; wn.len()];
wn_copy.copy_from_slice(wn);
match dtrsl(
&mut wn_copy,
2 * m,
col,
&mut wn[js * wn_dim..],
11, ) {
Ok(_) => {
trace!("dtrsl successful for column {}", js);
},
Err(e) => {
warn!("dtrsl failed for column {} with error: {:?}", js, e);
return Err(-1); },
}
}
for is in (col)..col2 {
for js in is..col2 {
let mut sum = 0.0;
for k in 0..col {
sum += wn[is * wn_dim + k] * wn[js * wn_dim + k];
}
let mut d = ddot(col as i32, &wn[(is * wn_dim) as usize..], 1, &wn[js * wn_dim..], 1);
let idx = is + js * wn_dim;
wn[idx] += sum;
}
}
let upper_right_block_start = (col) + (col) * 2 * m;
let upper_right_block = &mut wn[upper_right_block_start..];
match dpofa(upper_right_block, 2 * m, col) {
Ok(_) => {
trace!("Lower right block Cholesky factorization successful");
},
Err(e) => {
warn!("Lower right block Cholesky factorization failed with error: {:?}", e);
return Err(-1); },
}
debug!("formk completed successfully");
Ok(())
}
pub fn formt(
m: usize,
wt: &mut [f64],
sy: &[f64],
ss: &[f64],
col: usize,
theta: f64,
) -> Result<(), LinpackError> {
for j in 0..col {
wt[j * m] = theta * ss[j * m];
}
for i in 1..col {
for j in i..col {
let k1 = (i.min(j) - 1) as usize;
let mut ddum = 0.0;
for k in 0..=k1 {
ddum += sy[i + k * m] * sy[j + k * m] / sy[k + k * m];
}
wt[i + j * m] = ddum + theta * ss[i + j * m];
}
}
dpofa(wt, m, col)?;
Ok(())
}
pub fn freev(
n: usize,
nfree: &mut usize,
index: &mut [i32],
nenter: &mut i32,
ileave: &mut i32,
indx2: &mut [i32],
iwhere: &[i32],
wrk: &mut bool,
updatd: bool,
cnstnd: bool,
iter: i32,
) {
*nenter = 0;
*ileave = n as i32 + 1;
if iter > 0 && cnstnd {
for i in 1..=*nfree {
let k = index[i-1];
if iwhere[k as usize - 1] > 0 {
*ileave -= 1;
indx2[*ileave as usize - 1] = k;
}
}
for i in (*nfree + 1)..=n {
let k = index[i-1];
if iwhere[k as usize - 1] <= 0 {
*nenter += 1;
indx2[*nenter as usize - 1] = k;
}
}
}
*wrk = *ileave < (n as i32 + 1) || *nenter > 0 || updatd;
*nfree = 0;
let mut iact = n;
for i in 1..=n {
let k = i;
if iwhere[k-1] <= 0 {
*nfree += 1;
index[*nfree-1] = k as i32;
} else {
iact -= 1;
index[iact] = k as i32;
}
}
debug!("{} variables are free at GCP iter {}", *nfree, iter + 1);
}
pub fn matupd(
n: usize,
m: usize,
ws: &mut [f64],
wy: &mut [f64],
sy: &mut [f64],
ss: &mut [f64],
d: &[f64],
r: &[f64],
itail: &mut usize,
iupdat: &mut usize,
col: &mut usize,
head: &mut usize,
theta: &mut f64,
rr: f64,
dr: f64,
stp: f64,
dtd: f64,
) -> i32 {
let wy_dim1 = n;
let sy_dim1 = m;
let ss_dim1 = m;
if *iupdat <= m {
*col = *iupdat;
*itail = (*head + *iupdat - 2) % m + 1;
} else {
*itail = *itail % m + 1;
*head = *head % m + 1;
}
let col_zero = *col - 1;
let itail_zero = *itail - 1;
for i in 0..n {
ws[(i + itail_zero * n) as usize] = d[i as usize];
}
for i in 0..n {
wy[(i + itail_zero * n) as usize] = r[i as usize];
}
*theta = rr / dr;
if *iupdat > m {
for j in 1..(*col as usize) {
for k in 0..j {
ss[k + (j-1) * (m as usize)] = ss[(k+1) + j * (m as usize)];
}
for k in j..(*col as usize) {
sy[k-1 + (j-1) * (m as usize)] = sy[k + j * (m as usize)];
}
}
}
let mut pointr = *head as usize;
for j in 1..(*col as usize) {
let j_idx = j - 1;
sy[(*col as usize - 1) + j_idx * (m as usize)] = ddot(n as i32, d, 1, &wy[((pointr-1) * (wy_dim1 as usize)) as usize..], 1);
ss[j_idx + (*col as usize - 1) * (m as usize)] = ddot(n as i32, &ws[((pointr-1) * (wy_dim1 as usize)) as usize..], 1, d, 1);
pointr = pointr % (m as usize) + 1;
}
if stp == 1.0 {
ss[(col_zero + col_zero * ss_dim1) as usize] = dtd;
} else {
ss[(col_zero + col_zero * ss_dim1) as usize] = stp * stp * dtd;
}
sy[(col_zero + col_zero * sy_dim1) as usize] = dr;
0 }
pub fn projgr(
n: usize,
l: &[f64],
u: &[f64],
nbd: &[i32],
x: &[f64],
g: &[f64],
) -> f64 {
let mut sbgnrm = 0.0f64;
for i in 0..n {
let mut gi = g[i];
if nbd[i] != 0 {
if gi < 0.0 {
if nbd[i] >= 2 {
gi = f64::max(x[i] - u[i], gi);
}
} else if nbd[i] <= 2 {
gi = f64::min(x[i] - l[i], gi);
}
}
sbgnrm = f64::max(sbgnrm, gi.abs());
}
sbgnrm
}
pub fn compute_newton_direction(
nsub: usize,
ind: &[i32],
d: &mut [f64],
ws: &[f64],
wy: &[f64],
wv: &mut [f64],
wn: &[f64],
theta: f64,
col: usize,
head: usize,
m: usize,
n: usize,
) -> Result<(), i32> {
let m2 = 2 * m;
let col2 = 2 * col;
let mut pointr = head;
for i in 1..=col {
let mut temp1 = 0.0f64;
let mut temp2 = 0.0f64;
for j in 1..=nsub {
let k = ind[j-1] as usize;
temp1 += wy[(k-1) + (pointr-1) * n] * d[j-1];
temp2 += ws[(k-1) + (pointr-1) * n] * d[j-1];
}
wv[i-1] = temp1;
wv[(col + i)-1] = theta * temp2;
pointr = pointr % m + 1;
}
let mut wn_copy = vec![0.0; wn.len()];
wn_copy.copy_from_slice(wn);
match dtrsl(
&mut wn_copy,
m2,
col2,
&mut wv[0..col2],
C_11 ) {
Ok(_) => {},
Err(_) => return Err(-1),
}
for i in 0..col {
wv[i] = -wv[i];
}
match dtrsl(
&mut wn_copy,
m2,
col2,
&mut wv[0..col2],
C_1 ) {
Ok(_) => {},
Err(_) => return Err(-1),
}
pointr = head;
for jy in 1..=col {
let js = col + jy;
for i in 1..=nsub {
let k = ind[i-1] as usize;
d[i-1] = d[i-1] +
wy[(k-1) + (pointr-1) * n] * wv[jy-1] / theta +
ws[(k-1) + (pointr-1) * n] * wv[js-1];
}
pointr = pointr % m + 1;
}
let scale = 1.0 / theta;
for i in 0..nsub {
d[i] *= scale;
}
Ok(())
}
fn project_onto_feasible_region(
nsub: usize,
ind: &[i32],
d: &[f64],
x: &mut [f64],
xp: &mut [f64],
l: &[f64],
u: &[f64],
nbd: &[i32],
n: usize,
) -> bool {
xp[0..n].copy_from_slice(&x[0..n]);
let mut iword = 0;
for i in 1..=nsub {
let k = ind[i-1] as usize;
let dk = d[i-1];
let xk = x[k-1];
if nbd[k-1] != 0 {
if nbd[k-1] == 1 {
x[k-1] = f64::max(l[k-1], xk + dk);
if x[k-1] == l[k-1] {
iword = 1;
}
} else if nbd[k-1] == 2 {
let xk_new = f64::max(l[k-1], xk + dk);
x[k-1] = f64::min(u[k-1], xk_new);
if x[k-1] == l[k-1] || x[k-1] == u[k-1] {
iword = 1;
}
} else if nbd[k-1] == 3 {
x[k-1] = f64::min(u[k-1], xk + dk);
if x[k-1] == u[k-1] {
iword = 1;
}
}
} else {
x[k-1] = xk + dk;
}
}
iword != 0
}
fn backtrack_if_needed(
nsub: usize,
ind: &[i32],
d: &mut [f64],
x: &mut [f64],
xp: &[f64],
xx: &[f64],
gg: &[f64],
l: &[f64],
u: &[f64],
nbd: &[i32],
n: usize,
) {
let mut dd_p = 0.0f64;
for i in 0..n {
dd_p += (x[i] - xx[i]) * gg[i];
}
if dd_p > 0.0f64 {
x[0..n].copy_from_slice(&xp[0..n]);
let mut alpha = 1.0f64;
let mut ibd = 0;
for i in 1..=nsub {
let k = ind[i-1] as usize;
let dk = d[i-1];
if nbd[k-1] != 0 {
if dk < 0.0f64 && nbd[k-1] <= 2 {
let temp2 = l[k-1] - x[k-1];
if temp2 >= 0.0f64 {
alpha = 0.0f64;
} else if dk * alpha < temp2 {
alpha = temp2 / dk;
ibd = i;
}
} else if dk > 0.0f64 && nbd[k-1] >= 2 {
let temp2 = u[k-1] - x[k-1];
if temp2 <= 0.0f64 {
alpha = 0.0f64;
} else if dk * alpha > temp2 {
alpha = temp2 / dk;
ibd = i;
}
}
}
}
if alpha < 1.0f64 && ibd > 0 {
let dk = d[ibd-1];
let k = ind[ibd-1] as usize;
if dk > 0.0f64 {
x[k-1] = u[k-1];
d[ibd-1] = 0.0f64;
} else if dk < 0.0f64 {
x[k-1] = l[k-1];
d[ibd-1] = 0.0f64;
}
}
for i in 1..=nsub {
let k = ind[i-1] as usize;
x[k-1] += alpha * d[i-1];
}
}
}
pub fn subsm(
n: usize,
m: usize,
nsub: usize,
ind: &[i32],
l: &[f64],
u: &[f64],
nbd: &[i32],
d: &mut [f64],
x: &mut [f64],
xp: &mut [f64],
xx: &[f64],
gg: &[f64],
ws: &[f64],
wy: &[f64],
theta: f64,
col: usize,
head: usize,
wv: &mut [f64],
wn: &[f64],
) -> i32 {
debug!("----------------- enter SUBSM --------------");
let mut iword = 0;
match compute_newton_direction(
nsub,
ind,
d,
ws,
wy,
wv,
wn,
theta,
col,
head,
m,
n,
) {
Ok(_) => {},
Err(err_code) => {
debug!("compute_newton_direction failed with error code: {}", err_code);
debug!("----------------- exit SUBSM (early) --------------");
return 0;
}
}
let hit_boundary = project_onto_feasible_region(
nsub,
ind,
d,
x,
xp,
l,
u,
nbd,
n,
);
if hit_boundary {
iword = 1;
backtrack_if_needed(
nsub,
ind,
d,
x,
xp,
xx,
gg,
l,
u,
nbd,
n,
);
}
debug!("----------------- exit SUBSM --------------");
return iword;
}