def is_quasiconvex(self) -> bool: """Is the expression quaisconvex? """ from cvxpy.atoms.max import max as max_atom # Verifies the DQCP composition rule. if self.is_convex(): return True if type(self) in (cvxtypes.maximum(), max_atom): return all(arg.is_quasiconvex() for arg in self.args) non_const = self._non_const_idx() if self._is_real() and self.is_incr(non_const[0]): return self.args[non_const[0]].is_quasiconvex() if self._is_real() and self.is_decr(non_const[0]): return self.args[non_const[0]].is_quasiconcave() if self.is_atom_quasiconvex(): for idx, arg in enumerate(self.args): if not (arg.is_affine() or (arg.is_convex() and self.is_incr(idx)) or (arg.is_concave() and self.is_decr(idx))): return False return True return False
def is_quasiconvex(self): """Is the expression quaisconvex? """ # Verifies the DQCP composition rule. if self.is_convex(): return True if type(self) == cvxtypes.maximum(): return all(arg.is_quasiconvex() for arg in self.args) non_const = self._non_const_idx() if self.is_scalar() and len(non_const) == 1 and self.is_incr(non_const[0]): # TODO(akshayka): Accommodate vector atoms if people want it. return self.args[non_const[0]].is_quasiconvex() if self.is_scalar() and len(non_const) == 1 and self.is_decr(non_const[0]): return self.args[non_const[0]].is_quasiconcave() if self.is_atom_quasiconvex(): for idx, arg in enumerate(self.args): if not (arg.is_affine() or (arg.is_convex() and self.is_incr(idx)) or (arg.is_concave() and self.is_decr(idx))): return False return True return False