def test_signed_curvature(self): # Convex argument. expr = cvx.abs(1 + cvx.exp(cvx.Variable())) self.assertEqual(expr.curvature, s.CONVEX) expr = cvx.abs(-cvx.entr(cvx.Variable())) self.assertEqual(expr.curvature, s.UNKNOWN) expr = cvx.abs(-cvx.log(cvx.Variable())) self.assertEqual(expr.curvature, s.UNKNOWN) # Concave argument. expr = cvx.abs(cvx.log(cvx.Variable())) self.assertEqual(expr.curvature, s.UNKNOWN) expr = cvx.abs(-cvx.square(cvx.Variable())) self.assertEqual(expr.curvature, s.CONVEX) expr = cvx.abs(cvx.entr(cvx.Variable())) self.assertEqual(expr.curvature, s.UNKNOWN) # Affine argument. expr = cvx.abs(cvx.NonNegative()) self.assertEqual(expr.curvature, s.CONVEX) expr = cvx.abs(-cvx.NonNegative()) self.assertEqual(expr.curvature, s.CONVEX) expr = cvx.abs(cvx.Variable()) self.assertEqual(expr.curvature, s.CONVEX)
def test_dcp_curvature(self): expr = 1 + cvx.exp(cvx.Variable()) self.assertEqual(expr.curvature, s.CONVEX) expr = cvx.Parameter() * cvx.NonNegative() self.assertEqual(expr.curvature, s.AFFINE) f = lambda x: x**2 + x**0.5 expr = f(cvx.Constant(2)) self.assertEqual(expr.curvature, s.CONSTANT) expr = cvx.exp(cvx.Variable())**2 self.assertEqual(expr.curvature, s.CONVEX) expr = 1 - cvx.sqrt(cvx.Variable()) self.assertEqual(expr.curvature, s.CONVEX) expr = cvx.log(cvx.sqrt(cvx.Variable())) self.assertEqual(expr.curvature, s.CONCAVE) expr = -(cvx.exp(cvx.Variable()))**2 self.assertEqual(expr.curvature, s.CONCAVE) expr = cvx.log(cvx.exp(cvx.Variable())) self.assertEqual(expr.is_dcp(), False) expr = cvx.entr(cvx.NonNegative()) self.assertEqual(expr.curvature, s.CONCAVE) expr = ((cvx.Variable()**2)**0.5)**0 self.assertEqual(expr.curvature, s.CONSTANT)
def calculateEmbeddingMatrix( D, verbose=False, target_dist=1.1, jlt_tries=30 ): assert isMetricSpaceMatrix(D) n = D.shape[0] if int(cvx.__version__.split(".")[0]) == 0: Q = cvx.Semidef(n) d = cvx.NonNegative() else: Q = cvx.Variable(shape=(n, n), PSD=True) d = cvx.Variable(shape=(1, 1), nonneg=True) # print(D) # c = matrix(([1]*n)) log.debug("Generating constraints for embedding:") log.debug(f"Distance matrix: {D}") constraints = [] for i in range(n): for j in range(i, n): constraints += [D[i, j] ** 2 <= Q[i, i] + Q[j, j] - 2 * Q[i, j]] constraints += [ Q[i, i] + Q[j, j] - 2 * Q[i, j] <= d * D[i, j] ** 2 ] log.debug( f"adding constraint: {D[i,j]}**2 <= Q{[i,i]} + Q{[j,j]} - 2*Q{[i,j]}" ) log.debug( f"adding constraint: Q{[i,i]} + Q{[j,j]} - 2*Q{[i,j]} <= d * {D[i,j]}**2 " ) obj = cvx.Minimize(d) prob = cvx.Problem(obj, constraints) solvers = cvx.installed_solvers() if "MOSEK" in solvers: log.info("Solving problem with MOSEK solver") prob.solve(solver=cvx.MOSEK, verbose=verbose) elif "CVXOPT" in solvers: prob.solve( solver=cvx.CVXOPT, kktsolver=cvx.ROBUST_KKTSOLVER, verbose=verbose, ) log.info("Solving problem with CVXOPT solver") else: prob.solve(verbose=verbose) log.warning( "CVXOPT not installed. Solving problem with default solver." ) if prob.status != cvx.OPTIMAL: log.warning( "embedding optimization status non-optimal: " + str(prob.status) ) return None, None # print(Q.value) # print(np.linalg.eigvals(np.matrix(Q.value))) # print(np.linalg.eigh(np.matrix(Q.value))) # print(type(np.matrix(Q.value))) # print(np.matrix(Q.value)) try: L = np.linalg.cholesky(np.array(Q.value)) except np.linalg.LinAlgError: eigenvals, eigenvecs = np.linalg.eigh(np.array(Q.value)) min_eigenv = min(eigenvals) if min_eigenv < 0: log.warning( "Warning, matrix not positive semidefinite." + "Trying to correct for numerical errors with minimal eigenvalue: " + str(min_eigenv) + " (max. eigenvalue:" + str(max(eigenvals)) + ")." ) Q_new_t = ( np.transpose(eigenvecs) @ np.array(Q.value) @ eigenvecs ) # print(eigenvals) # print(Q_new_t) # should be = diagonal(eigenvalues) # print(np.transpose(eigenvecs) * eigenvecs) # should be = Identity matrix Q_new_t += np.diag([-min_eigenv] * len(eigenvals)) Q_new = eigenvecs @ Q_new_t @ np.transpose(eigenvecs) L = np.linalg.cholesky(Q_new) log.debug(f"Shape of lower-triangular matrix L: {L.shape}") lowerdim, d = jlt_search(D, L, target_dist, num_tries=jlt_tries) # print(lowerdim) # return L,d.value return lowerdim, d