pyblm/sandbox/powerit/sympowerit.py

101 lines
2.7 KiB
Python

from numpy import *
HAS_SYMPOWER=True
try:
from _numpy_module import sym_powerit
except:
raise ImportError("Sym_powerit module not present")
HAS_SYMPOWER = False
class SymPowerException(Exception):
pass
_ERRORCODES = {1: "Some eigenvectors did not converge, try to increase \nthe number of iterations or lower the tolerance level",
0: ""}
def sympowerit(xx, T0=None, mn_center=False, a_max=10, tol=1e-7, maxiter=100,
verbose=0):
"""Estimate eigenvectos of a symmetric matrix using the power method.
*Parameters*:
xx : {array}
Symmetric square array (m, m)
T0 : {array}
Initial solution (m, a_max), optional
mn_center : {boolean}, optional
Mean centering
a_max : {integer}, optional
Number of components to extract
tol : {float}, optional
Tolerance level of eigenvector solver
maxiter : {integer}
Maximum number of poweriterations to use
verbose : {integer}
Debug output (==1)
*Returns*:
v : {array}
Eigenvectors of xx, (m , a_max)
"""
valid_types = ['D','d','F','f']
dtype = xx.dtype.char
n, m = xx.shape
if not(dtype in valid_types):
msg = "Array type: (%s) needs to be a float or double" %dtype
raise SymPowerException(msg)
if not (m==n):
msg = "Input array needs to be square, input: (%d,%d)" %(m,n)
raise SymPowerException(msg)
# small test of symmetry
N = 5
num = random.randint(0,n,N)
for i in range(5):
j = N-5
if abs(xx[num[i],num[j]] - xx[num[j],num[i]])>1e-15:
msg = "Array needs to be symmetric"
raise SymPowerException(msg)
if not a_max:
a_max = 10
if T0 !=None:
tn, tm = T0.shape
if not (tn==n):
msg = "Start eigenvectors need to match input array ()"
raise SymPowerException(msg)
if not (tm==a_max):
msg = "Start eigenvectors need to match input a_max ()"
raise SymPowerException(msg)
else:
T0 = zeros((n, a_max), 'd')
T0[0,:] = ones((a_max,),'d')
if mn_center:
xx = _center(xx)
# call c-function
T, info = sym_powerit(xx, T0, n, a_max, tol, maxiter, verbose)
if info != 0:
if verbose:
print _ERRORCODES.get(info, "Dont know this error")
return T
def _center(xx, ret_mn=False):
"""Returns mean centered symmetric kernel matrix.
"""
n = xx.shape[0]
h = xx.sum(0)[:,newaxis]
h = (h - mean(h)/2)/n
mn_a = h + h.T
xxc = xx - mn_a
if ret_mn:
return xxc, mn_a
return xxc