ellalgo-rs 0.1.1

Ellipsoid Method in Rust
Documentation
use ndarray::Array2;
use ndarray::Array1;
use ndarray::Axis;
use ndarray::s;
use ndarray::stack;
use ndarray::Array;
use ndarray::ArrayView;
use ndarray::ArrayViewMut;
use ndarray::Array2;
use ndarray::Array1;
use ndarray::Axis;
use ndarray::s;
use ndarray::stack;
use ndarray::Array;
use ndarray::ArrayView;
use ndarray::ArrayViewMut;

type Arr = Array2<f64>;
type Cut = (Arr, f64);

struct LowpassOracle {
    A: Arr,
    nwpass: usize,
    nwstop: usize,
    Lpsq: f64,
    Upsq: f64,
    more_alt: bool,
}

impl LowpassOracle {
    fn new(A: Arr, nwpass: usize, nwstop: usize, Lpsq: f64, Upsq: f64) -> Self {
        LowpassOracle {
            A,
            nwpass,
            nwstop,
            Lpsq,
            Upsq,
            more_alt: true,
        }
    }

    fn assess_optim(&mut self, x: ArrayView<f64, ndarray::Ix1>, Spsq: f64) -> (Cut, Option<f64>) {
        let n = x.len();
        self.more_alt = true;

        for k in 0..self.nwpass {
            let v = self.A.slice(s![k, ..]).dot(&x);
            if v > self.Upsq {
                let g = self.A.slice(s![k, ..]);
                let f = (v - self.Upsq, v - self.Lpsq);
                return ((g, f), None);
            }

            if v < self.Lpsq {
                let g = -self.A.slice(s![k, ..]);
                let f = (-v + self.Lpsq, -v + self.Upsq);
                return ((g, f), None);
            }
        }

        let mut fmax = f64::NEG_INFINITY;
        let mut imax = 0;
        for k in self.nwstop..self.A.shape()[0] {
            let v = self.A.slice(s![k, ..]).dot(&x);
            if v > Spsq {
                let g = self.A.slice(s![k, ..]);
                let f = (v - Spsq, v);
                return ((g, f), None);
            }

            if v < 0.0 {
                let g = -self.A.slice(s![k, ..]);
                let f = (-v, -v + Spsq);
                return ((g, f), None);
            }

            if v > fmax {
                fmax = v;
                imax = k;
            }
        }

        for k in self.nwpass..self.nwstop {
            let v = self.A.slice(s![k, ..]).dot(&x);
            if v < 0.0 {
                let f = -v;
                let g = -self.A.slice(s![k, ..]);
                return ((g, f), None);
            }
        }

        self.more_alt = false;

        if x[0] < 0.0 {
            let g = Array1::zeros(n);
            g[[0]] = -1.0;
            let f = -x[0];
            return ((g, f), None);
        }

        let Spsq = fmax;
        let f = (0.0, fmax);
        let g = self.A.slice(s![imax, ..]);
        ((g, f), Some(Spsq))
    }
}

fn create_lowpass_case(N: usize) -> (LowpassOracle, f64) {
    let delta0_wpass = 0.025;
    let delta0_wstop = 0.125;
    let delta1 = 20.0 * (delta0_wpass).log10();
    let delta2 = 20.0 * (delta0_wstop).log10();

    let m = 15 * N;
    let w = Array::linspace(0.0, std::f64::consts::PI, m);
    let An = Array::from_shape_fn((m, N - 1), |(i, j)| 2.0 * (w[i] * (j + 1) as f64).cos());
    let A = stack![Axis(1), Array::ones(m).insert_axis(Axis(1)), An];
    let nwpass = (0.12 * (m - 1) as f64).floor() as usize + 1;
    let nwstop = (0.20 * (m - 1) as f64).floor() as usize + 1;
    let Lp = (10.0f64).powf(-delta1 / 20.0);
    let Up = (10.0f64).powf(delta1 / 20.0);
    let Sp = (10.0f64).powf(delta2 / 20.0);
    let Lpsq = Lp * Lp;
    let Upsq = Up * Up;
    let Spsq = Sp * Sp;

    let omega = LowpassOracle::new(A, nwpass, nwstop, Lpsq, Upsq);
    (omega, Spsq)
}