pub struct BallP<'a, T = f64> { /* private fields */ }Expand description
An $\ell_p$ ball, that is, $$B_p^r = \{ x \in R^n : \Vert x \Vert_p \leq r \}$$ or a translated ball $$B_p^{x_c, r} = \{ x \in \mathbb{R}^n : \Vert x - x_c \Vert_p \leq r \},$$ with $1 < p < \infty$.
§Projection problem
Given a vector $x$, projection onto the ball means solving
$$\Pi_{B_p^r}(x) = \mathrm{argmin}_{z \in B_p^r} \frac{1}{2}\Vert z - x \Vert_2^2.$$
If $x$ already belongs to the ball, the projection is $x$ itself. Otherwise, the projection lies on the boundary of the ball.
§Numerical method
For general $1 < p < \infty$, the projection does not admit a simple closed-form expression. This implementation computes it numerically using the optimality conditions of the constrained problem.
For a ball centered at the origin, the projection is characterized by
$$z_i = \operatorname{sign}(x_i),u_i(\lambda),$$
where each scalar $u_i(\lambda) \geq 0$ solves
$$u_i + \lambda p,u_i^{p-1} = |x_i|,$$
and the Lagrange multiplier $\lambda \geq 0$ is chosen so that the projected vector satisfies the feasibility condition $|z|_p = r.$
The implementation uses:
- an outer bisection loop to determine the multiplier $\lambda$,
- an inner safeguarded Newton method to solve the scalar nonlinear equation for each coordinate.
The Newton iteration is combined with bracketing and a bisection fallback, which improves robustness.
§Translated balls
If the ball has a center $x_c$, projection is performed by translating the input vector to the origin, projecting onto the origin-centered ball, and translating the result back:
$$\Pi_{B_p^{x_c, r}}(x) = x_c + \Pi_{B_p^r}(x - x_c).$$
§Convexity
Since this module assumes p > 1.0, every BallP is convex, and therefore
Constraint::project computes a unique Euclidean projection.
§Examples
Project onto the unit (\ell_p)-ball centered at the origin:
use optimization_engine::constraints::{BallP, Constraint};
let ball = BallP::new(None, 1.0, 1.5, 1e-10, 100);
let mut x = vec![3.0, -1.0, 2.0];
ball.project(&mut x).unwrap();Project onto a translated (\ell_p)-ball:
use optimization_engine::constraints::{BallP, Constraint};
let center = vec![1.0, 1.0, 1.0];
let ball = BallP::new(Some(¢er), 2.0, 3.0, 1e-10, 100);
let mut x = vec![4.0, -1.0, 2.0];
ball.project(&mut x).unwrap();§Notes
- The projection is with respect to the Euclidean norm
- The implementation is intended for general finite $p > 1.0$. If you need
to project on a $\Vert{}\cdot{}\Vert_1$-ball or an $\Vert{}\cdot{}\Vert_\infty$-ball,
use the implementations in
Ball1andBallInf. - Do not use this struct to project on a Euclidean ball; the implementation
in
Ball2is more efficient - The quality and speed of the computation depend on the chosen numerical tolerance and iteration limit.
Implementations§
Source§impl<'a, T: Float> BallP<'a, T>
impl<'a, T: Float> BallP<'a, T>
Sourcepub fn new(
center: Option<&'a [T]>,
radius: T,
p: T,
tolerance: T,
max_iter: usize,
) -> Self
pub fn new( center: Option<&'a [T]>, radius: T, p: T, tolerance: T, max_iter: usize, ) -> Self
Construct a new l_p ball with given center, radius, and exponent.
center: ifNone, the ball is centered at the originradius: radius of the ballp: norm exponent, must satisfyp > 1.0and be finitetolerance: tolerance for the numerical solversmax_iter: maximum number of iterations for the numerical solvers