def huber(x, M=1): """The Huber function Huber(x, M) = 2M|x|-M^2 for |x| >= |M| |x|^2 for |x| <= |M| M defaults to 1. Parameters ---------- x : Expression A CVXPY expression. M : int/float """ # TODO require that M is positive? return square(M)*huber_pos(abs(x)/abs(M))
def huber(x, M=1): """The Huber function Huber(x, M) = 2M|x|-M^2 for |x| >= |M| |x|^2 for |x| <= |M| M defaults to 1. Parameters ---------- x : Expression A CVXPY expression. M : int/float """ # TODO require that M is positive? return square(M) * huber_pos(abs(x) / abs(M))
def norm1_canon(expr, args): x = args[0] axis = expr.axis # we need an absolute value constraint for the symmetric convex branches # (p >= 1) constraints = [] # TODO(akshayka): Express this more naturally (recursively), in terms # of the other atoms abs_expr = abs(x) abs_x, abs_constraints = abs_canon(abs_expr, abs_expr.args) constraints += abs_constraints return sum(abs_x, axis=axis), constraints
def pnorm_canon(expr, args): x = args[0] p = expr.p axis = expr.axis shape = expr.shape t = Variable(shape) if p == 2: if axis is None: assert shape == tuple() return t, [SOC(t, vec(x))] else: return t, [SOC(vec(t), x, axis)] # we need an absolute value constraint for the symmetric convex branches # (p > 1) constraints = [] if p > 1: # TODO(akshayka): Express this more naturally (recursively), in terms # of the other atoms abs_expr = abs(x) abs_x, abs_constraints = abs_canon(abs_expr, abs_expr.args) x = abs_x constraints += abs_constraints # now, we take care of the remaining convex and concave branches # to create the rational powers, we need a new variable, r, and # the constraint sum(r) == t r = Variable(x.shape) constraints += [sum(r) == t] # todo: no need to run gm_constr to form the tree each time. # we only need to form the tree once promoted_t = Constant(np.ones(x.shape)) * t p = Fraction(p) if p < 0: constraints += gm_constrs(promoted_t, [x, r], (-p / (1 - p), 1 / (1 - p))) if 0 < p < 1: constraints += gm_constrs(r, [x, promoted_t], (p, 1 - p)) if p > 1: constraints += gm_constrs(x, [r, promoted_t], (1 / p, 1 - 1 / p)) return t, constraints
def huber_canon(expr, args): M = expr.M x = args[0] shape = expr.shape n = Variable(shape) s = Variable(shape) # n**2 + 2*M*|s| # TODO(akshayka): Make use of recursion inherent to canonicalization # process and just return a power / abs expressions for readability sake power_expr = power(n, 2) n2, constr_sq = power_canon(power_expr, power_expr.args) abs_expr = abs(s) abs_s, constr_abs = abs_canon(abs_expr, abs_expr.args) obj = n2 + 2 * M * abs_s constraints = constr_sq + constr_abs constraints.append(x == s + n) return obj, constraints