1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use super::Constraint;

///
/// A finite set, `X = {x1, x2, ..., xn}`, where `xi` are given vectors
/// of equal dimensions.
///
pub struct FiniteSet {
    /// The data is stored in a Vec-of-Vec datatype, that is, a vector
    /// of vectors
    data: Vec<Vec<f64>>,
}

impl FiniteSet {
    /// Construct a finite set, `X = {x1, x2, ..., xn}`, given vectors
    /// `xi` of equal dimensions
    ///
    ///
    /// ### Parameters
    ///
    /// - data: vector of vectors (see example below)
    ///
    ///
    /// ### Example
    ///
    /// ```
    /// use optimization_engine::constraints::*;
    ///
    /// let data: Vec<Vec<f64>> = vec![
    ///    vec![0.0, 0.0],
    ///    vec![1.0, 1.0],
    ///    vec![0.0, 1.0],
    ///    vec![1.0, 0.0],
    /// ];
    /// let finite_set = FiniteSet::new(data);
    /// ```
    ///
    ///
    /// ### Panics
    ///
    /// This method will panic if (i) the given vector of data is empty
    /// and (ii) if the given vectors have unequal dimensions.
    ///
    pub fn new(data: Vec<Vec<f64>>) -> Self {
        // Do a sanity check...
        assert!(data.len() > 0, "empty data not allowed");
        let n = data[0].len();
        for v in data.iter() {
            assert!(n == v.len(), "inconsistent dimensions");
        }
        FiniteSet { data: data }
    }
}

impl<'a> Constraint for FiniteSet {
    ///
    /// Projection on the current finite set
    ///
    /// Traverses the elements of the vector, computes norm-2 distances
    /// to each element, and updates the given vector `x` with the closest
    /// element from the finite set.
    ///
    ///
    /// ### Parameters
    ///
    /// - x: (input) given vector, (output) projection on finite set
    ///
    ///
    /// ### Example
    ///
    /// ```
    /// use optimization_engine::constraints::*;
    ///
    /// let data: Vec<Vec<f64>> = vec![
    ///    vec![0.0, 0.0],
    ///    vec![1.0, 1.0],
    /// ];
    /// let finite_set = FiniteSet::new(data);
    /// let mut x = [0.7, 0.6];
    /// finite_set.project(&mut x); // compute projection
    /// ```
    ///
    /// ### Panics
    ///
    /// Does not panic
    ///
    fn project(&self, x: &mut [f64]) {
        let mut idx: usize = 0;
        let mut best_distance: f64 = num::Float::infinity();
        for (i, v) in self.data.iter().enumerate() {
            let dist = crate::matrix_operations::norm2_squared_diff(v, x);
            if dist < best_distance {
                idx = i;
                best_distance = dist;
            }
        }
        x.copy_from_slice(&self.data[idx]);
    }
}