def __mul__(self, other): """Determines the DCP attributes of two expressions multiplied together. Assumes one of the arguments has constant curvature. Args: self: The DCPAttr of the left-hand expression. other: The DCPAttr of the right-hand expression. Returns: The DCPAttr of the product. """ shape = self.shape * other.shape sign = self.sign * other.sign if self.curvature.is_constant(): curvature = Curvature.sign_mul(self.sign, other.curvature) else: curvature = Curvature.sign_mul(other.sign, self.curvature) return DCPAttr(sign, curvature, shape)
def mul_elemwise(lh_expr, rh_expr): """Determines the DCP attributes of expressions multiplied elementwise. Assumes the left-hand argument has constant curvature and both arguments have the same shape. Args: lh_expr: The DCPAttr of the left-hand expression. rh_expr: The DCPAttr of the right-hand expression. Returns: The DCPAttr of the product. """ shape = lh_expr.shape + rh_expr.shape sign = lh_expr.sign * rh_expr.sign curvature = Curvature.sign_mul(lh_expr.sign, rh_expr.curvature) return DCPAttr(sign, curvature, shape)
def dcp_curvature(monotonicity, func_curvature, arg_sign, arg_curvature): """Applies DCP composition rules to determine curvature in each argument. Composition rules: Key: Function curvature + monotonicity + argument curvature == curvature in argument anything + anything + constant == constant anything + anything + affine == original curvature convex/affine + increasing + convex == convex convex/affine + decreasing + concave == convex concave/affine + increasing + concave == concave concave/affine + decreasing + convex == concave Notes: Increasing (decreasing) means non-decreasing (non-increasing). Any combinations not covered by the rules result in a nonconvex expression. Args: monotonicity: The monotonicity of the function in the given argument. func_curvature: The curvature of the function. arg_sign: The sign of the given argument. arg_curvature: The curvature of the given argument. Returns: The Curvature of the composition of function and arguments. """ if arg_curvature.is_constant(): return Curvature.CONSTANT elif monotonicity == INCREASING: return func_curvature + arg_curvature elif monotonicity == DECREASING: return func_curvature - arg_curvature # Absolute value style monotonicity. elif monotonicity == SIGNED and \ func_curvature.is_convex(): conc_mat = arg_sign.neg_mat & arg_curvature.cvx_mat | \ arg_sign.pos_mat & arg_curvature.conc_mat return Curvature(np.bool_(True), conc_mat, np.bool_(True)) else: # non-monotonic return func_curvature + arg_curvature - arg_curvature