]> gitweb.michael.orlitzky.com - dunshire.git/blobdiff - dunshire/matrices.py
A bunch more doc fixes.
[dunshire.git] / dunshire / matrices.py
index 66c21768403f19e8affa18fe23d1ffdf4f0ecd16..f35827d16be600cec3ee5d1c2d0fbcea27a9484d 100644 (file)
@@ -3,9 +3,10 @@ Utility functions for working with CVXOPT matrices (instances of the
 class:`cvxopt.base.matrix` class).
 """
 
+from copy import copy
 from math import sqrt
 from cvxopt import matrix
-from cvxopt.lapack import gees, syevr
+from cvxopt.lapack import gees, gesdd, syevr
 
 from . import options
 
@@ -17,8 +18,11 @@ def append_col(left, right):
     Parameters
     ----------
 
-    left, right : matrix
-        The two matrices to append to one another.
+    left : matrix
+        The "original" matrix, the one that will wind up on the left.
+
+    right : matrix
+        The matrix to be appended on the right of ``left``.
 
     Returns
     -------
@@ -56,8 +60,11 @@ def append_row(top, bottom):
     Parameters
     ----------
 
-    top, bottom : matrix
-        The two matrices to append to one another.
+    top : matrix
+        The "original" matrix, the one that will wind up on top.
+
+    bottom : matrix
+        The matrix to be appended below ``top``.
 
     Returns
     -------
@@ -140,7 +147,10 @@ def eigenvalues(symmat):
 
     domain_dim = symmat.size[0]
     eigs = matrix(0, (domain_dim, 1), tc='d')
-    syevr(symmat, eigs)
+
+    # Create a copy of ``symmat`` here because ``syevr`` clobbers it.
+    dummy = copy(symmat)
+    syevr(dummy, eigs)
     return list(eigs)
 
 
@@ -261,8 +271,11 @@ def inner_product(vec1, vec2):
     Parameters
     ----------
 
-    vec1, vec2 : matrix
-        The two vectors whose inner product you want.
+    vec1 : matrix
+        The first vector, whose inner product with ``vec2`` you want.
+
+    vec2 : matrix
+        The second vector, whose inner product with ``vec1`` you want.
 
     Returns
     -------
@@ -326,17 +339,53 @@ def norm(matrix_or_vector):
     --------
 
         >>> v = matrix([1,1])
-        >>> print('{:.5f}'.format(norm(v)))
-        1.41421
+        >>> norm(v)
+        1.414...
 
         >>> A = matrix([1,1,1,1], (2,2))
         >>> norm(A)
-        2.0
+        2.0...
 
     """
     return sqrt(inner_product(matrix_or_vector, matrix_or_vector))
 
 
+def specnorm(mat):
+    """
+    Return the spectral norm of a matrix.
+
+    The spectral norm of a matrix is its largest singular value, and it
+    corresponds to the operator norm induced by the vector Euclidean norm.
+
+    Parameters
+    ----------
+
+    mat : matrix
+        The matrix whose spectral norm you want.
+
+    Examples:
+
+        >>> specnorm(identity(3))
+        1.0
+
+        >>> specnorm(5*identity(4))
+        5.0
+
+    """
+    num_eigs = min(mat.size)
+    eigs = matrix(0, (num_eigs, 1), tc='d')
+    typecode = 'd'
+    if any([isinstance(entry, complex) for entry in mat]):
+        typecode = 'z'
+    dummy = matrix(mat, mat.size, tc=typecode)
+    gesdd(dummy, eigs)
+
+    if len(eigs) > 0:
+        return eigs[0]
+    else:
+        return 0
+
+
 def vec(mat):
     """
     Create a long vector in column-major order from ``mat``.
@@ -388,3 +437,57 @@ def vec(mat):
 
     """
     return matrix(mat, (len(mat), 1))
+
+
+def condition_number(mat):
+    """
+    Return the condition number of the given matrix.
+
+    The condition number of a matrix quantifies how hard it is to do
+    numerical computation with that matrix. It is usually defined as
+    the ratio of the norm of the matrix to the norm of its inverse, and
+    therefore depends on the norm used. One way to compute the condition
+    number with respect to the 2-norm is as the ratio of the matrix's
+    largest and smallest singular values. Since we have easy access to
+    those singular values, that is the algorithm we use.
+
+    The larger the condition number is, the worse the matrix is.
+
+    Parameters
+    ----------
+    mat : matrix
+        The matrix whose condition number you want.
+
+    Returns
+    -------
+
+    float
+        The nonnegative condition number of ``mat``.
+
+    Examples
+    --------
+
+    >>> condition_number(identity(3))
+    1.0
+
+    >>> A = matrix([[2,1],[1,2]])
+    >>> abs(condition_number(A) - 3.0) < options.ABS_TOL
+    True
+
+    >>> A = matrix([[2,1j],[-1j,2]])
+    >>> abs(condition_number(A) - 3.0) < options.ABS_TOL
+    True
+
+    """
+    num_eigs = min(mat.size)
+    eigs = matrix(0, (num_eigs, 1), tc='d')
+    typecode = 'd'
+    if any([isinstance(entry, complex) for entry in mat]):
+        typecode = 'z'
+    dummy = matrix(mat, mat.size, tc=typecode)
+    gesdd(dummy, eigs)
+
+    if len(eigs) > 0:
+        return eigs[0]/eigs[-1]
+    else:
+        return 0