def setup_RPn_cost(D, return_grad=False): """Create the cost functions for pymanopt. The cost function is given by F(X) = (1/2)*||W * |X^T X| - cos(D))||^2 Where `W` is the weight matrix accounting for removing the arccos term. Currently only returns the cost. For better performance, could add gradient as a return value. Parameters ---------- D : ndarray (n, n) Matrix of target distances. Returns ------- cost : function Weighted Frobenius norm cost function. egrad : function Gradient (in Euclidean space) of cost function. """ W = distance_to_weights(D) C = np.cos(D) def cost(Y): """Weighted Frobenius norm cost function.""" return 0.5 * np.linalg.norm(W * (C - np.abs(Y.T @ Y)))**2 def egrad(Y): """Derivative of the cost function.""" return 2 * Y @ (W**2 * (np.abs(Y.T @ Y) - C) * np.sign(Y.T @ Y)) return cost, egrad
def setup_CPn_cost(D, n, return_grad=False): """Cost using geodesic metric on CPn.""" W = distance_to_weights(D) C = np.cos(D)**2 i_mtx = np.vstack((np.hstack((np.zeros( (n, n)), -np.eye(n))), np.hstack((np.eye(n), np.zeros((n, n)))))) def cost(Y): return 0.5 * np.linalg.norm(W * ((Y.T @ Y)**2 + (Y.T @ (i_mtx @ Y))**2 - C))**2 if return_grad: def egrad(Y): J = np.vstack((np.hstack((np.zeros( (n, n)), np.eye(n))), np.zeros((n, 2 * n)))) R = np.vstack((np.hstack((np.eye(n), np.zeros( (n, n)))), np.zeros((n, 2 * n)))) return (Y @ (2 * (Y.T @ Y)) @ (2 * (W * ((Y.T @ Y)**2 + (Y.T @ (i_mtx @ Y))**2 - C))) + (R @ Y + J @ Y) @ (2 * (Y.T @ J @ Y)) @ (2 * (W * ( (Y.T @ Y)**2 + (Y.T @ (i_mtx @ Y))**2 - C)))) else: egrad = None return cost, egrad
def setup_CPn_cost(D, n, return_grad=False): """Cost using geodesic metric on CPn.""" W = distance_to_weights(D) i_mtx = np.vstack((np.hstack((np.zeros( (n, n)), -np.eye(n))), np.hstack((np.eye(n), np.zeros((n, n)))))) def cost(Y): return 0.5 * np.linalg.norm( np.sqrt((Y.T @ Y)**2 + (Y.T @ (i_mtx @ Y))**2) - D)**2 return cost, None