def normNuc_canon(expr, args): A = args[0] m, n = A.shape # Create the equivalent problem: # minimize (trace(U) + trace(V))/2 # subject to: # [U A; A.T V] is positive semidefinite constraints = [] U = Variable(shape=(m, m), symmetric=True) V = Variable(shape=(n, n), symmetric=True) X = bmat([[U, A], [A.T, V]]) constraints.append(X >> 0) trace_value = 0.5 * (trace(U) + trace(V)) return trace_value, constraints
def lambda_sum_largest(X, k): """Sum of the largest k eigenvalues. """ X = Expression.cast_to_const(X) if X.size[0] != X.size[1]: raise ValueError("First argument must be a square matrix.") elif int(k) != k or k <= 0: raise ValueError("Second argument must be a positive integer.") """ S_k(X) denotes lambda_sum_largest(X, k) t >= k S_k(X - Z) + trace(Z), Z is PSD implies t >= ks + trace(Z) Z is PSD sI >= X - Z (PSD sense) which implies t >= ks + trace(Z) >= S_k(sI + Z) >= S_k(X) We use the fact that S_k(X) = sup_{sets of k orthonormal vectors u_i}\sum_{i}u_i^T X u_i and if Z >= X in PSD sense then \sum_{i}u_i^T Z u_i >= \sum_{i}u_i^T X u_i We have equality when s = lambda_k and Z diagonal with Z_{ii} = (lambda_i - lambda_k)_+ """ Z = Semidef(X.size[0]) return k*lambda_max(X - Z) + trace(Z)
def normNuc_canon(expr, args): A = args[0] m, n = A.shape # Create the equivalent problem: # minimize (trace(U) + trace(V))/2 # subject to: # [U A; A.T V] is positive semidefinite X = Variable((m + n, m + n), PSD=True) constraints = [] # Fix X using the fact that A must be affine by the DCP rules. # X[0:rows,rows:rows+cols] == A constraints.append(X[0:m, m:m + n] == A) trace_value = 0.5 * trace(X) return trace_value, constraints