Example #1
0
    def test_subgradient(self):
        """Check if the subgradient is computed correctly

        Subgradient should lie in the cone made up by the subgradients.

        """
        c = CConstraintL1(center=0, radius=1)

        x0 = CArray([0, 1])

        p_min = CArray([1, 1])
        p_max = CArray([-1, 1])

        gradient = c.gradient(x0)

        # normalize the points
        norm_center = x0 / x0.norm(2)
        norm_p_min = p_min / p_min.norm(2)
        norm_p_max = p_max / p_max.norm(2)
        norm_gradient = gradient / gradient.norm(2)

        angl1 = round(acos(norm_center.dot(norm_gradient)), 5)
        angl2 = round(acos(norm_p_min.dot(norm_p_max)) / 2.0, 5)

        self.logger.info("Subgrad in {:} is:\n{:}".format(x0, gradient))

        self.assertLessEqual(angl1, angl2, "Subgrad is not inside the cone of "
                                           "{:} and {:}".format(p_min, p_max))
Example #2
0
    def _xk(self, x, fx, *args):
        """Returns a new point after gradient descent."""

        # compute gradient
        grad = self._fun.gradient(x, *args)
        self._grad = grad  # only used for visualization/convergence

        norm = grad.norm()
        if norm < 1e-20:
            return x, fx  # return same point (and exit optimization)

        grad = grad / norm

        # filter modifications that would violate bounds (to sparsify gradient)
        grad = self._box_projected_gradient(x, grad)

        if self.constr is not None and self.constr.class_type == 'l1':
            # project z onto l1 constraint (via dual norm)
            grad = self._l1_projected_gradient(grad)

        next_point = CArray(x - grad * self._line_search.eta,
                            dtype=self._dtype,
                            tosparse=x.issparse)

        if self.constr is not None and self.constr.is_violated(next_point):
            self.logger.debug("Line-search on distance constraint.")
            grad = CArray(x - self.constr.projection(next_point))
            grad_norm = grad.norm(order=2)
            if grad_norm > 1e-20:
                grad /= grad_norm
            if self.constr.class_type == 'l1':
                grad = grad.sign()  # to move along the l1 ball surface
            z, fz = self._line_search.minimize(x, -grad, fx)
            return z, fz

        if self.bounds is not None and self.bounds.is_violated(next_point):
            self.logger.debug("Line-search on box constraint.")
            grad = CArray(x - self.bounds.projection(next_point))
            grad_norm = grad.norm(order=2)
            if grad_norm > 1e-20:
                grad /= grad_norm
            z, fz = self._line_search.minimize(x, -grad, fx)
            return z, fz

        z, fz = self._line_search.minimize(x, -grad, fx)
        return z, fz