ellalgo_rs/
quasicvx.rs

1use super::cutting_plane::OracleOptim;
2use ndarray::prelude::*;
3
4type Arr = Array1<f64>;
5
6#[derive(Debug)]
7pub struct MyOracle {
8    idx: i32,
9}
10
11impl Default for MyOracle {
12    fn default() -> Self {
13        MyOracle { idx: -1 }
14    }
15}
16
17impl OracleOptim<Arr> for MyOracle {
18    type CutChoice = f64; // single cut
19
20    /// The function assesses optimization based on input values and returns a tuple along with a
21    /// boolean flag.
22    ///
23    /// Arguments:
24    ///
25    /// * `xc`: The `xc` parameter in the `assess_optim` function represents an array containing two
26    ///         elements. The first element, `xc[0]`, is assigned to the variable `sqrtx`, and the second
27    ///         element, `xc[1]`, is assigned to the variable `logy`. These
28    /// * `gamma`: The `gamma` parameter is a mutable reference to a `f64` value. It is being updated
29    ///         within the `assess_optim` function based on the calculations performed on the input values `xc`
30    ///         and the internal state of the function.
31    fn assess_optim(&mut self, xc: &Arr, gamma: &mut f64) -> ((Arr, f64), bool) {
32        let sqrtx = xc[0];
33        let logy = xc[1];
34
35        let num_constraints = 2;
36        for _ in 0..num_constraints {
37            self.idx += 1;
38            if self.idx == num_constraints {
39                self.idx = 0; // round robin
40            }
41            let fj = match self.idx {
42                0 => sqrtx * sqrtx - logy,
43                1 => -sqrtx + *gamma * logy.exp(),
44                _ => unreachable!(),
45            };
46            if fj > 0.0 {
47                return (
48                    (
49                        match self.idx {
50                            0 => array![2.0 * sqrtx, -1.0],
51                            1 => array![-1.0, *gamma * logy.exp()],
52                            _ => unreachable!(),
53                        },
54                        fj,
55                    ),
56                    false,
57                );
58            }
59        }
60        *gamma = sqrtx / logy.exp();
61        ((array![-1.0, sqrtx], 0.0), true)
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::MyOracle;
68    use crate::cutting_plane::{cutting_plane_optim, Options};
69    use crate::ell::Ell;
70    // use crate::ell_stable::EllStable;
71    use ndarray::array;
72
73    #[test]
74    pub fn test_feasible() {
75        let mut ell = Ell::new(array![10.0, 10.0], array![0.0, 0.0]);
76        let mut oracle = MyOracle::default();
77        let mut gamma = 0.0;
78        let options = Options {
79            max_iters: 2000,
80            tolerance: 1e-8,
81        };
82        let (x_opt, num_iters) = cutting_plane_optim(&mut oracle, &mut ell, &mut gamma, &options);
83        assert!(x_opt.is_some());
84        if let Some(x) = x_opt {
85            assert!(x[0] * x[0] >= 0.49 && x[0] * x[0] <= 0.51);
86            assert!(x[1].exp() >= 1.6 && x[1].exp() <= 1.7);
87        }
88        assert_eq!(num_iters, 35);
89    }
90
91    // #[test]
92    // pub fn test_feasible_stable() {
93    //     let mut ell = EllStable::new(array![10.0, 10.0], array![0.0, 0.0]);
94    //     let mut oracle = MyOracle::default();
95    //     let mut gamma = 0.0;
96    //     let options = Options {
97    //         max_iters: 2000,
98    //         tolerance: 1e-8,
99    //     };
100    //     let (x_opt, num_iters) = cutting_plane_optim(&mut oracle, &mut ell, &mut gamma, &options);
101    //     assert!(x_opt.is_some());
102    //     if let Some(x) = x_opt {
103    //         assert!(x[0] * x[0] >= 0.49 && x[0] * x[0] <= 0.51);
104    //         assert!(x[1].exp() >= 1.6 && x[1].exp() <= 1.7);
105    //     }
106    //     assert_eq!(num_iters, 35);
107    // }
108}