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
use super::Constraint;
use crate::matrix_operations;
#[derive(Clone)]
/// A hyperplane is a set given by $H = \\{x \in \mathbb{R}^n {}:{} \langle c, x\rangle = b\\}$.
pub struct Hyperplane<'a> {
/// normal vector
normal_vector: &'a [f64],
/// offset
offset: f64,
/// squared Euclidean norm of the normal vector (computed once upon construction)
normal_vector_squared_norm: f64,
}
impl<'a> Hyperplane<'a> {
/// A hyperplane is a set given by $H = \\{x \in \mathbb{R}^n {}:{} \langle c, x\rangle = b\\}$,
/// where $c$ is the normal vector of the hyperplane and $b$ is an offset.
///
/// This method constructs a new instance of `Hyperplane` with a given normal
/// vector and bias
///
/// # Arguments
///
/// - `normal_vector`: the normal vector, $c$, as a slice
/// - `offset`: the offset parameter, $b$
///
/// # Returns
///
/// New instance of `Hyperplane`
///
/// # Panics
///
/// Does not panic. Note: it does not panic if you provide an empty slice as `normal_vector`,
/// but you should avoid doing that.
///
/// # Example
///
/// ```
/// use optimization_engine::constraints::{Constraint, Hyperplane};
///
/// let normal_vector = [1., 2.];
/// let offset = 1.0;
/// let hyperplane = Hyperplane::new(&normal_vector, offset);
/// let mut x = [-1., 3.];
/// hyperplane.project(&mut x);
/// ```
///
pub fn new(normal_vector: &'a [f64], offset: f64) -> Self {
let normal_vector_squared_norm = matrix_operations::norm2_squared(normal_vector);
Hyperplane {
normal_vector,
offset,
normal_vector_squared_norm,
}
}
}
impl<'a> Constraint for Hyperplane<'a> {
/// Projects on the hyperplane using the formula:
///
/// $$\begin{aligned}
/// \mathrm{proj}_{H}(x) =
/// x - \frac{\langle c, x\rangle - b}
/// {\\|c\\|}c.
/// \end{aligned}$$
///
/// where $H = \\{x \in \mathbb{R}^n {}:{} \langle c, x\rangle = b\\}$
///
/// # Arguments
///
/// - `x`: (in) vector to be projected on the current instance of a hyperplane,
/// (out) projection on the second-order cone
///
/// # Panics
///
/// This method panics if the length of `x` is not equal to the dimension
/// of the hyperplane.
///
fn project(&self, x: &mut [f64]) {
let inner_product = matrix_operations::inner_product(x, self.normal_vector);
let factor = (inner_product - self.offset) / self.normal_vector_squared_norm;
x.iter_mut()
.zip(self.normal_vector.iter())
.for_each(|(x, nrm_vct)| *x -= factor * nrm_vct);
}
/// Hyperplanes are convex sets
///
/// # Returns
///
/// Returns `true`
fn is_convex(&self) -> bool {
true
}
}