# Source code for cvxpy.atoms.sigma_max

"""

This file is part of CVXPY.

CVXPY is free software: you can redistribute it and/or modify
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

CVXPY is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with CVXPY.  If not, see <http://www.gnu.org/licenses/>.
"""

from cvxpy.atoms.atom import Atom
import scipy.sparse as sp
from numpy import linalg as LA
import numpy as np

[docs]class sigma_max(Atom):
""" Maximum singular value. """
_allow_complex = True

def __init__(self, A):
super(sigma_max, self).__init__(A)

@Atom.numpy_numeric
def numeric(self, values):
"""Returns the largest singular value of A.
"""
return LA.norm(values[0], 2)

"""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.
"""
U, s, V = LA.svd(values[0])
ds = np.zeros(len(s))
ds[0] = 1
D = U.dot(np.diag(ds)).dot(V)
return [sp.csc_matrix(D.ravel(order='F')).T]

def shape_from_args(self):
"""Returns the (row, col) shape of the expression.
"""
return tuple()

def sign_from_args(self):
"""Returns sign (is positive, is negative) of the expression.
"""
# Always positive.
return (True, False)

def is_atom_convex(self):
"""Is the atom convex?
"""
return True

def is_atom_concave(self):
"""Is the atom concave?
"""
return False

def is_incr(self, idx):
"""Is the composition non-decreasing in argument idx?
"""
return False

def is_decr(self, idx):
"""Is the composition non-increasing in argument idx?
"""
return False