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))
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