def _grad(self, values): """Gives the (sub/super)gradient of the atom w.r.t. each argument. Matrix expressions are vectorized, so the gradient is a matrix. Args: values: A list of numeric values for the arguments. Returns: A list of SciPy CSC sparse matrices or None. """ rows = self.args[0].size[0]*self.args[0].size[1] cols = self.size[0]*self.size[1] if self.p == 0: # All zeros. return [sp.csc_matrix((rows, cols), dtype='float64')] # Outside domain or on boundary. if not is_power2(self.p) and np.min(values[0]) <= 0: if self.p < 1: # Non-differentiable. return [None] else: # Round up to zero. values[0] = np.maximum(values[0], 0) grad_vals = float(self.p)*np.power(values[0], float(self.p)-1) return [power.elemwise_grad_to_diag(grad_vals, rows, cols)]
def _grad(self, values): """Gives the (sub/super)gradient of the atom w.r.t. each argument. Matrix expressions are vectorized, so the gradient is a matrix. Args: values: A list of numeric values for the arguments. Returns: A list of SciPy CSC sparse matrices or None. """ rows = self.args[0].size[0] * self.args[0].size[1] cols = self.size[0] * self.size[1] if self.p == 0: # All zeros. return [sp.csc_matrix((rows, cols), dtype='float64')] # Outside domain or on boundary. if not is_power2(self.p) and np.min(values[0]) <= 0: if self.p < 1: # Non-differentiable. return [None] else: # Round up to zero. values[0] = np.maximum(values[0], 0) grad_vals = float(self.p) * np.power(values[0], float(self.p) - 1) return [power.elemwise_grad_to_diag(grad_vals, rows, cols)]
def _domain(self): """Returns constraints describing the domain of the node. """ if (self.p < 1 and not self.p == 0) or \ (self.p > 1 and not is_power2(self.p)): return [self.args[0] >= 0] else: return []
def is_decr(self, idx): """Is the composition non-increasing in argument idx? """ if self.p <= 0: return True elif self.p > 1: if is_power2(self.p): return self.args[idx].is_negative() else: return False else: return False
def numeric(self, values): # Throw error if negative and power doesn't handle that. if self.p < 0 and values[0].min() <= 0: raise ValueError( "power(x, %.1f) cannot be applied to negative or zero values." % float(self.p)) elif not is_power2(self.p) and self.p != 0 and values[0].min() < 0: raise ValueError( "power(x, %.1f) cannot be applied to negative values." % float(self.p)) else: return np.power(values[0], float(self.p))
def is_incr(self, idx): """Is the composition non-decreasing in argument idx? """ if 0 <= self.p <= 1: return True elif self.p > 1: if is_power2(self.p): return self.args[idx].is_nonneg() else: return True else: return False
def monotonicity(self): if self.p == 0: return [u.monotonicity.INCREASING] if self.p == 1: return [u.monotonicity.INCREASING] if self.p < 0: return [u.monotonicity.DECREASING] if 0 < self.p < 1: return [u.monotonicity.INCREASING] if self.p > 1: if is_power2(self.p): return [u.monotonicity.SIGNED] else: return [u.monotonicity.INCREASING]
def _domain(self): """Returns constraints describing the domain of the node. """ if not isinstance(self._p_orig, cvxtypes.expression()): p = self._p_orig else: p = self.p.value if p is None: raise ValueError("Cannot compute domain of parametrized power when " "parameter value is unspecified.") elif (p < 1 and not p == 0) or (p > 1 and not is_power2(p)): return [self.args[0] >= 0] else: return []
def is_decr(self, idx) -> bool: """Is the composition non-increasing in argument idx? """ if not _is_const(self.p): return self.p.is_nonpos() and self.args[idx].is_nonneg() p = self.p_rational if p <= 0: return True elif p > 1: if is_power2(p): return self.args[idx].is_nonpos() else: return False else: return False
def _grad(self, values): """Gives the (sub/super)gradient of the atom w.r.t. each argument. Matrix expressions are vectorized, so the gradient is a matrix. Args: values: A list of numeric values for the arguments. Returns: A list of SciPy CSC sparse matrices or None. """ rows = self.args[0].size cols = self.size if self.p_rational is not None: p = self.p_rational elif self.p.value is not None: p = self.p.value else: raise ValueError("Cannot compute grad of parametrized power when " "parameter value is unspecified.") if p == 0: # All zeros. return [sp.csc_matrix((rows, cols), dtype='float64')] # Outside domain or on boundary. if not is_power2(p) and np.min(values[0]) <= 0: if p < 1: # Non-differentiable. return [None] else: # Round up to zero. values[0] = np.maximum(values[0], 0) grad_vals = float(p) * np.power(values[0], float(p) - 1) return [power.elemwise_grad_to_diag(grad_vals, rows, cols)]