def prox_sum_quantile(expr): arg = None if (expr.expression_type == Expression.SUM and expr.arg[0].expression_type == Expression.MAX_ELEMENTWISE and len(expr.arg[0].arg) == 2): alpha, x = get_quantile_arg(expr.arg[0].arg[0]) beta, y = get_quantile_arg(expr.arg[0].arg[1]) if (x is not None and y is not None and x == y): if (alpha.sign.sign_type == Sign.NEGATIVE and beta.sign.sign_type == Sign.POSITIVE): alpha, beta = beta, expression.negate(alpha) arg = x elif (alpha.sign.sign_type == Sign.POSITIVE and beta.sign.sign_type == Sign.NEGATIVE): beta = expression.negate(beta) arg = x if not arg: return MatchResult(False) alpha = linear.transform_expr(alpha) beta = linear.transform_expr(beta) diagonal_arg, constrs = convert_diagonal(arg) return MatchResult( True, expression.prox_function( create_prox( prox_function_type=ProxFunction.SUM_QUANTILE, arg_size=[Size(dim=dims(arg))], scaled_zone_params=ProxFunction.ScaledZoneParams( alpha_expr=alpha.proto_with_args, beta_expr=beta.proto_with_args)), diagonal_arg), constrs)
def transform_norm_p(expr): p = expr.p x = only_arg(expr) t = epi_var(expr, "norm_p", size=(1,1)) if p == float("inf"): return t, [expression.leq_constraint(x, t), expression.leq_constraint(expression.negate(x), t)] if p == 1: return transform_expr(expression.sum_entries(expression.abs_val(x))) if p == 2: return t, [expression.soc_constraint(t, x)] r = epi_var(expr, "norm_p_r", size=dims(x)) t1 = expression.multiply(expression.ones(*dims(x)), t) if p < 0: p, _ = power_tools.pow_neg(p) p = Fraction(p) constrs = gm_constrs(t1, [x, r], (-p/(1-p), 1/(1-p))) elif 0 < p < 1: p, _ = power_tools.pow_mid(p) p = Fraction(p) constrs = gm_constrs(r, [x, t1], (p, 1-p)) elif p > 1: abs_x, constrs = transform_expr(expression.abs_val(x)) p, _ = power_tools.pow_high(p) p = Fraction(p) constrs += gm_constrs(abs_x, [r, t1], (1/p, 1-1/p)) constrs.append(expression.eq_constraint(expression.sum_entries(r), t)) return t, constrs
def transform_abs(expr): x = only_arg(expr) t = epi_var(expr, "abs") return t, [ expression.leq_constraint(x, t), expression.leq_constraint(expression.negate(x), t) ]
def epi(f_expr, t_expr): """An expression for an epigraph constraint. The constraint depends on the curvature of f: - f convex, I(f(x) <= t) - f concave, I(f(x) >= t) - f affine, I(f(x) == t) """ f_curvature = f_expr.dcp_props.curvature.curvature_type if f_curvature == Curvature.CONVEX: return expression.leq_constraint(f_expr, t_expr) elif f_curvature == Curvature.CONCAVE: return expression.leq_constraint(expression.negate(f_expr), expression.negate(t_expr)) elif f_curvature == Curvature.AFFINE: return expression.eq_constraint(f_expr, t_expr) raise TransformError( "Unknown curvature: %s" % Curvature.Type.Name(f_curvature), f_expr)
def epi(f_expr, t_expr): """An expression for an epigraph constraint. The constraint depends on the curvature of f: - f convex, I(f(x) <= t) - f concave, I(f(x) >= t) - f affine, I(f(x) == t) """ f_curvature = f_expr.dcp_props.curvature.curvature_type if f_curvature == Curvature.CONVEX: return expression.leq_constraint(f_expr, t_expr) elif f_curvature == Curvature.CONCAVE: return expression.leq_constraint( expression.negate(f_expr), expression.negate(t_expr)) elif f_curvature == Curvature.AFFINE: return expression.eq_constraint(f_expr, t_expr); raise TransformError( "Unknown curvature: %s" % Curvature.Type.Name(f_curvature), f_expr)
def prox_sum_quantile(expr): arg = None if (expr.expression_type == Expression.SUM and expr.arg[0].expression_type == Expression.MAX_ELEMENTWISE and len(expr.arg[0].arg) == 2): alpha, x = get_quantile_arg(expr.arg[0].arg[0]) beta, y = get_quantile_arg(expr.arg[0].arg[1]) if (x is not None and y is not None and x == y): if (alpha.sign.sign_type == Sign.NEGATIVE and beta.sign.sign_type == Sign.POSITIVE): alpha, beta = beta, expression.negate(alpha) arg = x elif (alpha.sign.sign_type == Sign.POSITIVE and beta.sign.sign_type == Sign.NEGATIVE): beta = expression.negate(beta) arg = x if not arg: return MatchResult(False) alpha = linear.transform_expr(alpha) beta = linear.transform_expr(beta) data = alpha.expression_data() data.update(beta.expression_data()) diagonal_arg, constrs = convert_diagonal(arg) return MatchResult( True, expression.prox_function( create_prox( prox_function_type=ProxFunction.SUM_QUANTILE, arg_size=[Size(dim=dims(arg))], scaled_zone_params=ProxFunction.ScaledZoneParams( alpha_expr=alpha.proto_with_args, beta_expr=beta.proto_with_args)), diagonal_arg, data=data), constrs)
def transform_quad_over_lin(expr): assert len(expr.arg) == 2 x, y = expr.arg assert dim(y) == 1 t = epi_var(expr, "qol", size=(1,1)) return t, [ expression.soc_constraint( expression.add(y, t), expression.vstack( expression.add(y, expression.negate(t)), expression.reshape( expression.multiply(expression.scalar_constant(2), x), dim(x), 1))), expression.leq_constraint(expression.scalar_constant(0), y)]
def get_epigraph(expr): if not (expr.expression_type == Expression.INDICATOR and expr.cone.cone_type == Cone.NON_NEGATIVE and not expr.arg[0].dcp_props.affine and expr.arg[0].expression_type == Expression.ADD and len(expr.arg[0].arg) == 2): return None, None exprs = expr.arg[0].arg for i in range(2): if exprs[i].dcp_props.affine: t_expr = exprs[i] f_expr = expression.negate(exprs[i - 1]) return f_expr, t_expr
def get_epigraph(expr): if not (expr.expression_type == Expression.INDICATOR and expr.cone.cone_type == Cone.NON_NEGATIVE and not expr.arg[0].dcp_props.affine and expr.arg[0].expression_type == Expression.ADD and len(expr.arg[0].arg) == 2): return None, None exprs = expr.arg[0].arg for i in xrange(2): if exprs[i].dcp_props.affine: t_expr = exprs[i] f_expr = expression.negate(exprs[i-1]) return f_expr, t_expr
def transform_quad_over_lin(expr): assert len(expr.arg) == 2 x, y = expr.arg assert dim(y) == 1 t = epi_var(expr, "qol", size=(1, 1)) return t, [ expression.soc_constraint( expression.add(y, t), expression.hstack( expression.add(y, expression.negate(t)), expression.reshape( expression.multiply(expression.scalar_constant(2), x), 1, dim(x)))), expression.leq_constraint(expression.scalar_constant(0), y) ]
def transform_norm_p(expr): p = expr.p x = only_arg(expr) t = epi_var(expr, "norm_p") if p == float("inf"): return t, [ expression.leq_constraint(x, t), expression.leq_constraint(expression.negate(x), t) ] if p == 1: return transform_expr(expression.sum_entries(expression.abs_val(x))) if p == 2: if not expr.has_axis: return t, [ expression.soc_constraint(t, expression.reshape(x, 1, dim(x))) ] if expr.axis == 0: return t, [ expression.soc_constraint(expression.reshape(t, dim(x, 1), 1), expression.transpose(x)) ] if expr.axis == 1: return t, [expression.soc_constraint(t, x)] r = epi_var(expr, "norm_p_r", size=dims(x)) t1 = expression.multiply(expression.ones(*dims(x)), t) if p < 0: p, _ = power_tools.pow_neg(p) p = Fraction(p) constrs = gm_constrs(t1, [x, r], (-p / (1 - p), 1 / (1 - p))) elif 0 < p < 1: p, _ = power_tools.pow_mid(p) p = Fraction(p) constrs = gm_constrs(r, [x, t1], (p, 1 - p)) elif p > 1: abs_x, constrs = transform_expr(expression.abs_val(x)) p, _ = power_tools.pow_high(p) p = Fraction(p) constrs += gm_constrs(abs_x, [r, t1], (1 / p, 1 - 1 / p)) constrs.append(expression.eq_constraint(expression.sum_entries(r), t)) return t, constrs
def transform_abs(expr): x = only_arg(expr) t = epi_var(expr, "abs") return t, [expression.leq_constraint(x, t), expression.leq_constraint(expression.negate(x), t)]
def gm(t, x, y): return expression.soc_elemwise_constraint( expression.add(x, y), expression.add(x, expression.negate(y)), expression.multiply(expression.scalar_constant(2), t))