.. _projections: Projections =========== For the api guide see :ref:`projections_api`. The ``suppy.projections`` module contains simple structures for projection operations as well as projection methods for projecting onto intersections. This guide covers the basic projection objects for the projection methods see :ref:`projection_methods`. As of now there are 5 elemental projection objects. Each one can be set up with a relaxation parameter and a flag to indicate whether to use the GPU for calculations. Furthermore indices can be set if the vector `x` to be projected and the constraint are not of the same dimension. The elemental projections are: .. _projections_BoxProjection: BoxProjection ------------- Projection onto box constraints of type :math:`\mathbf{a} \leq \mathbf{x} \leq \mathbf{b}`. Mathematically the projection is computed as :math:`\mathbf{P}(\mathbf{x}) = \min(\max(\mathbf{x}, \mathbf{a}), \mathbf{b})`. Setup of ``BoxProjection`` objects is as follows: .. code-block:: python import numpy as np from suppy.projections import BoxProjection a = np.array([0, 0]) b = np.array([1, 1]) projection = BoxProjection(a, b) where :math:`\mathbf{a}` and :math:`\mathbf{b}` are the lower and upper bounds of the constraint. WeightedBoxProjection --------------------- A "simultaneous" projection onto a box of type :math:`\mathbf{a} \leq \mathbf{x} \leq \mathbf{b}`. The idea is an analogon to the "sequential" projection in :ref:`projections_BoxProjection`. .. code-block:: python import numpy as np from suppy.projections import WeightedBoxProjection a = np.array([0, 0]) b = np.array([1, 1]) w = np.array([1/3,2/3]) projection = WeightedBoxProjection(a, b, w) where :math:`\mathbf{a}` and :math:`\mathbf{b}` are the lower and upper bounds of the constraint and :math:`\mathbf{w}` are the weights assigned to the individual bounds. HalfspaceProjection ------------------- Projection onto halfspaces of type :math:`\langle \mathbf{a},\mathbf{x} \rangle \leq \mathbf{b}`. .. code-block:: python import numpy as np from suppy.projections import HalfspaceProjection a = np.array([1, 1]) b = 1 projection = HalfspaceProjection(a, b) where :math:`\mathbf{a}` is the normal vector of the halfspace and :math:`\mathbf{b}` is the offset. Mathematically the performed calculation for the unrelaxed projection is .. math:: P(\mathbf{x}) = \begin{cases} \mathbf{x} - \frac{\langle \mathbf{a},\mathbf{x} \rangle - \mathbf{ub}}{||\mathbf{a}||^2} \mathbf{a} & \text{if } \langle \mathbf{a},\mathbf{x} \rangle \geq \mathbf{b} \\ \mathbf{x} & \text{otherwise}.\\ \end{cases} BandProjection -------------- Projection onto a band/hyperslab of type :math:`\langle \mathbf{lb},\mathbf{x} \rangle \leq \mathbf{ub}`. .. code-block:: python import numpy as np from suppy.projections import BandProjection a = np.array([1, 1]) lb = np.array([0, 0]) ub = np.array([1, 1]) projection = BandProjection(a, lb, ub) where :math:`\mathbf{lb}` and :math:`\mathbf{ub}` are the lower and upper bounds of the band/hyperslab and :math:`\mathbf{a}` is the normal vector. The projection is calculated as .. math:: P_{C_i}(\mathbf{x}) = \begin{cases} \mathbf{x} - \frac{\langle \mathbf{a},\mathbf{x} \rangle - \mathbf{ub}}{||\mathbf{a}||^2} \mathbf{a} & \text{if } \langle a,x \rangle \geq ub \\ \mathbf{x}\\ \mathbf{x} - \frac{\langle \mathbf{a},\mathbf{x} \rangle - \mathbf{lb}}{||\mathbf{a}||^2} \mathbf{a} & \text{if } \langle a,x \rangle \geq lb \\ \end{cases} BallProjection -------------- Projection onto a ball. .. code-block:: python import numpy as np from suppy.projections import BallProjection c = np.array([0, 0]) r = 1 projection = BallProjection(c, r) where :math:`\mathbf{c}` is the center of the ball and :math:`r` is the radius. Mathematically this is calculated as: .. math:: P(\mathbf{x}) = \begin{cases} \mathbf{c} + r \frac{\mathbf{x} - \mathbf{c}}{||\mathbf{x} - \mathbf{c}||} & \text{if } ||\mathbf{x} - \mathbf{c}|| > r \\ \mathbf{x} & \text{otherwise}.\\ \end{cases} .. _subgradient_projections: Subgradient projections ======================= If a constraint can be formulated as a convex continous function and its subgradient exist, a projection can be performed in the following way: .. code-block:: python import numpy as np from suppy.projections import SubgradientProjection def f(x): return np.linalg.norm(x) def subgrad_f(x): return x / np.linalg.norm(x) projection = SubgradientProjection(f, subgrad_f,level = 5) x = np.array([1, 1]) projection.project(x) where `f` is the function, `subgrad_f` its subgradient and `level` the level :math:`\alpha` giving :math:`f(x) \leq \alpha`. The projection is calculated as: .. math:: P(\mathbf{x}) = \begin{cases} \mathbf{x} - \frac{(f(\mathbf{x})-\alpha)_+}{||\nabla f(\mathbf{x})||^2} \nabla f(\mathbf{x}) & \text{if } f(\mathbf{x}) > \alpha \\ \mathbf{x} & \text{otherwise}.\\ \end{cases}