optimization_engine/constraints/halfspace.rs
1use super::Constraint;
2use crate::matrix_operations;
3
4#[derive(Clone)]
5/// A halfspace is a set given by $H = \\{x \in \mathbb{R}^n {}:{} \langle c, x\rangle \leq b\\}$.
6pub struct Halfspace<'a> {
7 /// normal vector
8 normal_vector: &'a [f64],
9 /// offset
10 offset: f64,
11 /// squared Euclidean norm of the normal vector (computed once upon construction)
12 normal_vector_squared_norm: f64,
13}
14
15impl<'a> Halfspace<'a> {
16 /// A halfspace is a set given by $H = \\{x \in \mathbb{R}^n {}:{} \langle c, x\rangle \leq b\\}$,
17 /// where $c$ is the normal vector of the halfspace and $b$ is an offset.
18 ///
19 /// This method constructs a new instance of `Halfspace` with a given normal
20 /// vector and bias
21 ///
22 /// # Arguments
23 ///
24 /// - `normal_vector`: the normal vector, $c$, as a slice
25 /// - `offset`: the offset parameter, $b$
26 ///
27 /// # Returns
28 ///
29 /// New instance of `Halfspace`
30 ///
31 /// # Panics
32 ///
33 /// Does not panic. Note: it does not panic if you provide an empty slice as `normal_vector`,
34 /// but you should avoid doing that.
35 ///
36 /// # Example
37 ///
38 /// ```
39 /// use optimization_engine::constraints::{Constraint, Halfspace};
40 ///
41 /// let normal_vector = [1., 2.];
42 /// let offset = 1.0;
43 /// let halfspace = Halfspace::new(&normal_vector, offset);
44 /// let mut x = [-1., 3.];
45 /// halfspace.project(&mut x);
46 /// ```
47 ///
48 pub fn new(normal_vector: &'a [f64], offset: f64) -> Self {
49 let normal_vector_squared_norm = matrix_operations::norm2_squared(normal_vector);
50 Halfspace {
51 normal_vector,
52 offset,
53 normal_vector_squared_norm,
54 }
55 }
56}
57
58impl<'a> Constraint for Halfspace<'a> {
59 /// Projects on halfspace using the following formula:
60 ///
61 /// $$\begin{aligned}
62 /// \mathrm{proj}_{H}(x) = \begin{cases}
63 /// x,& \text{ if } \langle c, x\rangle \leq b
64 /// \\\\
65 /// x - \frac{\langle c, x\rangle - b}
66 /// {\\|c\\|}c,& \text{else}
67 /// \end{cases}
68 /// \end{aligned}$$
69 ///
70 /// where $H = \\{x \in \mathbb{R}^n {}:{} \langle c, x\rangle \leq b\\}$
71 ///
72 /// # Arguments
73 ///
74 /// - `x`: (in) vector to be projected on the current instance of a halfspace,
75 /// (out) projection on the second-order cone
76 ///
77 /// # Panics
78 ///
79 /// This method panics if the length of `x` is not equal to the dimension
80 /// of the halfspace.
81 ///
82 fn project(&self, x: &mut [f64]) {
83 let inner_product = matrix_operations::inner_product(x, self.normal_vector);
84 if inner_product > self.offset {
85 let factor = (inner_product - self.offset) / self.normal_vector_squared_norm;
86 x.iter_mut()
87 .zip(self.normal_vector.iter())
88 .for_each(|(x, normal_vector_i)| *x -= factor * normal_vector_i);
89 }
90 }
91
92 /// Halfspaces are convex sets
93 ///
94 /// # Returns
95 ///
96 /// Returns `true`
97 fn is_convex(&self) -> bool {
98 true
99 }
100}