ellalgo_rs/
example4.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    #[inline]
13    fn default() -> Self {
14        MyOracle { idx: -1 }
15    }
16}
17
18impl OracleOptim<Arr> for MyOracle {
19    type CutChoice = f64; // single cut
20
21    /// The function assess_optim takes in two parameters, xc and gamma, and returns a tuple containing an
22    /// array and a double, along with a boolean value.
23    ///
24    /// Arguments:
25    ///
26    /// * `xc`: The parameter `xc` is an array of length 2, representing the values of `x` and `y`
27    ///         respectively.
28    /// * `gamma`: The parameter `gamma` is a mutable reference to a `f64` variable. It is used to store the
29    ///         current best solution for the optimization problem.
30    fn assess_optim(&mut self, xc: &Arr, gamma: &mut f64) -> ((Arr, f64), bool) {
31        let x = xc[0];
32        let y = xc[1];
33        let f0 = 2.0 * x - 3.0 * y;
34
35        let num_constraints = 4;
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 => -x - 1.0,
43                1 => -y - 2.0,
44                2 => x + y - 1.0,
45                3 => *gamma - f0,
46                _ => unreachable!(),
47            };
48            if fj > 0.0 {
49                return (
50                    (
51                        match self.idx {
52                            0 => array![-1.0, 0.0],
53                            1 => array![0.0, -1.0],
54                            2 => array![1.0, 1.0],
55                            3 => array![-2.0, 3.0],
56                            _ => unreachable!(),
57                        },
58                        fj,
59                    ),
60                    false,
61                );
62            }
63        }
64        *gamma = f0;
65        ((array![-2.0, 3.0], 0.0), true)
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use crate::cutting_plane::{cutting_plane_optim, Options};
73    use crate::ell::Ell;
74    // use ndarray::array;
75    // use super::ell_stable::EllStable;
76
77    /// Tests the feasibility of the optimization problem using the cutting plane method.
78    ///
79    /// This test creates a new `Ell` instance with a scalar radius of 10.0 and a center at `[0.0, 0.0]`.
80    /// It then creates a new `MyOracle` instance as the optimization oracle.
81    /// The `gamma` variable is initialized to negative infinity.
82    /// The `Options` struct is configured with a tolerance of 1e-10.
83    /// The `cutting_plane_optim` function is called with the oracle, ellipsoid, gamma, and options.
84    /// The test asserts that the best solution `xbest` is not `None`, and that the number of iterations is 25.
85    #[test]
86    pub fn test_feasible() {
87        let mut ellip = Ell::new_with_scalar(10.0, array![0.0, 0.0]);
88        let mut oracle = MyOracle::default();
89        let mut gamma = f64::NEG_INFINITY;
90        let options = Options {
91            tolerance: 1e-10,
92            ..Default::default()
93        };
94        let (xbest, num_iters) = cutting_plane_optim(&mut oracle, &mut ellip, &mut gamma, &options);
95        assert!(xbest.is_some());
96        assert_eq!(num_iters, 82);
97    }
98}