optimization_engine/constraints/hyperplane.rs
1use super::Constraint;
2use crate::matrix_operations;
3
4#[derive(Clone)]
5/// A hyperplane is a set given by $H = \\{x \in \mathbb{R}^n {}:{} \langle c, x\rangle = b\\}$.
6pub struct Hyperplane<'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> Hyperplane<'a> {
16 /// A hyperplane is a set given by $H = \\{x \in \mathbb{R}^n {}:{} \langle c, x\rangle = b\\}$,
17 /// where $c$ is the normal vector of the hyperplane and $b$ is an offset.
18 ///
19 /// This method constructs a new instance of `Hyperplane` 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 `Hyperplane`
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, Hyperplane};
40 ///
41 /// let normal_vector = [1., 2.];
42 /// let offset = 1.0;
43 /// let hyperplane = Hyperplane::new(&normal_vector, offset);
44 /// let mut x = [-1., 3.];
45 /// hyperplane.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 Hyperplane {
51 normal_vector,
52 offset,
53 normal_vector_squared_norm,
54 }
55 }
56}
57
58impl<'a> Constraint for Hyperplane<'a> {
59 /// Projects on the hyperplane using the formula:
60 ///
61 /// $$\begin{aligned}
62 /// \mathrm{proj}_{H}(x) =
63 /// x - \frac{\langle c, x\rangle - b}
64 /// {\\|c\\|}c.
65 /// \end{aligned}$$
66 ///
67 /// where $H = \\{x \in \mathbb{R}^n {}:{} \langle c, x\rangle = b\\}$
68 ///
69 /// # Arguments
70 ///
71 /// - `x`: (in) vector to be projected on the current instance of a hyperplane,
72 /// (out) projection on the second-order cone
73 ///
74 /// # Panics
75 ///
76 /// This method panics if the length of `x` is not equal to the dimension
77 /// of the hyperplane.
78 ///
79 fn project(&self, x: &mut [f64]) {
80 let inner_product = matrix_operations::inner_product(x, self.normal_vector);
81 let factor = (inner_product - self.offset) / self.normal_vector_squared_norm;
82 x.iter_mut()
83 .zip(self.normal_vector.iter())
84 .for_each(|(x, nrm_vct)| *x -= factor * nrm_vct);
85 }
86
87 /// Hyperplanes are convex sets
88 ///
89 /// # Returns
90 ///
91 /// Returns `true`
92 fn is_convex(&self) -> bool {
93 true
94 }
95}