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 transform_sum_largest(expr): x = only_arg(expr) k = expr.k q = epi_var(expr, "sum_largest") t = epi_var(expr, "sum_largest_t", size=dims(x)) obj = expression.add( expression.sum_entries(t), expression.multiply(expression.scalar_constant(k), q)) constr = [ expression.leq_constraint(x, expression.add(t, q)), expression.leq_constraint(expression.scalar_constant(0), t)] return obj, constr
def transform_sum_largest(expr): x = only_arg(expr) k = expr.k q = epi_var(expr, "sum_largest") t = epi_var(expr, "sum_largest_t", size=dims(x)) obj = expression.add(expression.sum_entries(t), expression.multiply(expression.scalar_constant(k), q)) constr = [ expression.leq_constraint(x, expression.add(t, q)), expression.leq_constraint(expression.scalar_constant(0), t) ] return obj, constr
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(negate(f_expr), negate(t_expr)) elif f_curvature == Curvature.AFFINE: return expression.eq_constraint(f_expr, t_expr); raise TransformError("Unknown curvature", f_expr)
def epigraph(expr): f_expr, t_expr = get_epigraph(expr) if f_expr: for rule in BASE_RULES: result = rule(f_expr) if result.match: epi_function = result.prox_expr.prox_function epi_function.epigraph = True epi_function.arg_size.add().CopyFrom(Size(dim=dims(t_expr))) linear_t_expr = linear.transform_expr(t_expr) if linear_t_expr.affine_props.scalar: constrs = [] else: linear_t_expr, constrs = epi_transform( linear_t_expr, "scalar") return MatchResult( True, expression.prox_function( epi_function, *(result.prox_expr.arg + [linear_t_expr])), result.raw_exprs + constrs) # No epigraph transform found, do conic transformation obj, constrs = conic.transform_expr(f_expr) return MatchResult( True, None, [expression.leq_constraint(obj, t_expr)] + constrs) # Not in epigraph form return MatchResult(False)
def transform_max_entries(expr): x = only_arg(expr) m, n = dims(x) t = epi_var(expr, "max_entries") if not expr.has_axis: return t, [expression.leq_constraint(x, t)] if expr.axis == 0: return t, [ expression.leq_constraint( x, expression.multiply(expression.ones(m, 1), t))] if expr.axis == 1: return t, [ expression.leq_constraint( x, expression.multiply(t, expression.ones(1, n)))] raise TransformError("unknown axis attribute", expr)
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 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 transform_max_entries(expr): x = only_arg(expr) m, n = dims(x) t = epi_var(expr, "max_entries") if not expr.has_axis: return t, [expression.leq_constraint(x, t)] if expr.axis == 0: return t, [ expression.leq_constraint( x, expression.multiply(expression.ones(m, 1), t)) ] if expr.axis == 1: return t, [ expression.leq_constraint( x, expression.multiply(t, expression.ones(1, n))) ] raise TransformError("unknown axis attribute", 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.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 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 epigraph(expr): f_expr, t_expr = get_epigraph(expr) if f_expr: for rule in BASE_RULES: result = rule(f_expr) if result.match: epi_function = result.prox_expr.prox_function epi_function.epigraph = True return MatchResult( True, expression.prox_function(epi_function, *(result.prox_expr.arg + [t_expr])), result.raw_exprs ) # No epigraph transform found, do conic transformation obj, constrs = conic.transform_expr(f_expr) return MatchResult(True, None, [expression.leq_constraint(obj, t_expr)] + constrs) # Not in epigraph form return MatchResult(False)
def convert_constraint(constraint): if isinstance(constraint, EqConstraint): return expression.eq_constraint(convert_expression(constraint.args[0]), convert_expression(constraint.args[1])) elif isinstance(constraint, PSDConstraint): return expression.psd_constraint( convert_expression(constraint.args[0]), convert_expression(constraint.args[1])) elif isinstance(constraint, LeqConstraint): return expression.leq_constraint( convert_expression(constraint.args[0]), convert_expression(constraint.args[1])) elif isinstance(constraint, SOC_Elemwise): return expression.soc_elemwise_constraint( convert_expression(constraint.t), *[convert_expression(x) for x in constraint.x_elems]) elif isinstance(constraint, SOC): return expression.soc_contraint( convert_expression(constraint.t), expression.vstack( *[convert_expression(x) for x in constraint.x_elems])) raise RuntimeError("Unknown constraint: %s" % type(constraint))
def convert_constraint(constraint): if isinstance(constraint, EqConstraint): return expression.eq_constraint( convert_expression(constraint.args[0]), convert_expression(constraint.args[1])) elif isinstance(constraint, PSDConstraint): return expression.psd_constraint( convert_expression(constraint.args[0]), convert_expression(constraint.args[1])) elif isinstance(constraint, LeqConstraint): return expression.leq_constraint( convert_expression(constraint.args[0]), convert_expression(constraint.args[1])) elif isinstance(constraint, SOC_Elemwise): return expression.soc_elemwise_constraint( convert_expression(constraint.t), *[convert_expression(x) for x in constraint.x_elems]) elif isinstance(constraint, SOC): return expression.soc_contraint( convert_expression(constraint.t), expression.vstack( *[convert_expression(x) for x in constraint.x_elems])) raise RuntimeError("Unknown constraint: %s" % type(constraint))
def transform_exp(expr): x = only_arg(expr) t = epi_var(expr, "exp") return t, [expression.leq_constraint(expr, t)]
def transform_min_elementwise(expr): t = epi_var(expr, "min_elementwise") return t, [expression.leq_constraint(t, x) for x in expr.arg]
def transform_min_elementwise(expr): t = epi_var(expr, "min") return t, [expression.leq_constraint(t, x) for x in expr.arg]
def transform_max_elementwise(expr): t = epi_var(expr, "max") return t, [expression.leq_constraint(x, t) for x in expr.arg]
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 transform_log(expr): x = only_arg(expr) t = epi_var(expr, "log") return t, [expression.leq_constraint(expression.exp(t), x)]