def __init__(self, x, p, max_denom=1024): p_old = p # how we convert p to a rational depends on the branch of the function if p > 1: p, w = pow_high(p, max_denom) elif 0 < p < 1: p, w = pow_mid(p, max_denom) elif p < 0: p, w = pow_neg(p, max_denom) # note: if, after making the rational approximation, p ends up being 0 or 1, # we default to using the 0 or 1 behavior of the atom, which affects the curvature, domain, etc... # maybe unexpected behavior to the user if they put in 1.00001? if p == 1: # in case p is a fraction equivalent to 1 p = 1 w = None if p == 0: p = 0 w = None self.p, self.w = p, w self.approx_error = float(abs(self.p - p_old)) super(power, self).__init__(x)
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 __init__(self, x, p, max_denom: int = 1024) -> None: self._p_orig = p # NB: It is important that the exponent is an attribute, not # an argument. This prevents parametrized exponents from being replaced # with their logs in Dgp2Dcp. self.p = cvxtypes.expression().cast_to_const(p) if not (isinstance(self.p, cvxtypes.constant()) or isinstance(self.p, cvxtypes.parameter())): raise ValueError( "The exponent `p` must be either a Constant or " "a Parameter; received ", type(p)) self.max_denom = max_denom self.p_rational = None if isinstance(self.p, cvxtypes.constant()): # Compute a rational approximation to p, for DCP (DGP doesn't need # an approximation). if not isinstance(self._p_orig, cvxtypes.expression()): # converting to a CVXPY Constant loses the dtype (eg, int), # so fetch the original exponent when possible p = self._p_orig else: p = self.p.value # how we convert p to a rational depends on the branch of the function if p > 1: p, w = pow_high(p, max_denom) elif 0 < p < 1: p, w = pow_mid(p, max_denom) elif p < 0: p, w = pow_neg(p, max_denom) # note: if, after making the rational approximation, p ends up # being 0 or 1, we default to using the 0 or 1 behavior of the # atom, which affects the curvature, domain, etc... maybe # unexpected behavior to the user if they put in 1.00001? if p == 1: # in case p is a fraction equivalent to 1 p = 1 w = None if p == 0: p = 0 w = None self.p_rational, self.w = p, w self.approx_error = float(abs(self.p_rational - p)) super(power, self).__init__(x)
def __init__(self, x, p=2, axis=None, keepdims=False, max_denom=1024): if p < 0: # TODO(akshayka): Why do we accept p < 0? self.p, _ = pow_neg(p, max_denom) elif 0 < p < 1: self.p, _ = pow_mid(p, max_denom) elif p > 1: self.p, _ = pow_high(p, max_denom) elif p == 1: raise ValueError('Use the norm1 class to instantiate a one norm.') elif p == 'inf' or p == 'Inf' or p == np.inf: raise ValueError('Use the norm_inf class to instantiate an ' 'infinity norm.') else: raise ValueError('Invalid p: {}'.format(p)) self.approx_error = float(abs(self.p - p)) super(Pnorm, self).__init__(x, axis=axis, keepdims=keepdims)
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 __init__(self, x, p=2, axis=None, max_denom=1024): p_old = p if p in ('inf', 'Inf', np.inf): self.p = np.inf elif p < 0: self.p, _ = pow_neg(p, max_denom) elif 0 < p < 1: self.p, _ = pow_mid(p, max_denom) elif p > 1: self.p, _ = pow_high(p, max_denom) elif p == 1: self.p = 1 else: raise ValueError('Invalid p: {}'.format(p)) super(pnorm, self).__init__(x, axis=axis) if self.p == np.inf: self.approx_error = 0 else: self.approx_error = float(abs(self.p - p_old))
def transform_power(expr): p = expr.p if p == 1: return only_arg(expr) one = expression.scalar_constant(1, size=dims(expr)) if p == 0: return one, [] t = epi_var(expr, "power") x = only_arg(expr) if p < 0: p, w = power_tools.pow_neg(p) constrs = gm_constrs(one, [x, t], w) if 0 < p < 1: p, w = power_tools.pow_mid(p) constrs = gm_constrs(t, [x, one], w) if p > 1: p, w = power_tools.pow_high(p) constrs = gm_constrs(x, [t, one], w) return t, constrs