-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlsqnonnegMatlabVersion.py
93 lines (67 loc) · 2.43 KB
/
lsqnonnegMatlabVersion.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import numpy
def lsqnonneg(C, d, x0=None, tol=None, itmax_factor=3):
'''Linear least squares with nonnegativity constraints.
(x, resnorm, residual) = lsqnonneg(C,d) returns the vector x that minimizes norm(d-C*x)
subject to x >= 0, C and d must be real
'''
eps = 2.22e-16 # from matlab
def norm1(x):
return abs(x).sum().max()
def msize(x, dim):
s = x.shape
if dim >= len(s):
return 1
else:
return s[dim]
if tol is None: tol = 10*eps*norm1(C)*(max(C.shape)+1)
C = numpy.asarray(C)
(m,n) = C.shape
P = numpy.zeros(n)
Z = numpy.arange(1, n+1)
if x0 is None: x=P
else:
if any(x0 < 0): x=P
else: x=x0
ZZ = Z
resid = d - numpy.dot(C, x)
w = numpy.dot(C.T, resid)
outeriter=0; it=0
itmax=itmax_factor*n
exitflag=1
# outer loop to put variables into set to hold positive coefficients
while numpy.any(Z) and numpy.any(w[ZZ-1] > tol):
outeriter += 1
t = w[ZZ-1].argmax()
t = ZZ[t]
P[t-1]=t
Z[t-1]=0
PP = numpy.where(P != 0)[0]+1
ZZ = numpy.where(Z != 0)[0]+1
CP = numpy.zeros(C.shape)
CP[:, PP-1] = C[:, PP-1]
CP[:, ZZ-1] = numpy.zeros((m, msize(ZZ, 1)))
z=numpy.dot(numpy.linalg.pinv(CP), d)
z[ZZ-1] = numpy.zeros((msize(ZZ,1), msize(ZZ,0)))
# inner loop to remove elements from the positve set which no longer belong
while numpy.any(z[PP-1] <= tol):
it += 1
if it > itmax:
max_error = z[PP-1].max()
raise Exception('Exiting: Iteration count (=%d) exceeded\n Try raising the \
tolerance tol. (max_error=%d)' % (it, max_error))
QQ = numpy.where((z <= tol) & (P != 0))[0]
alpha = min(x[QQ]/(x[QQ] - z[QQ]))
x = x + alpha*(z-x)
ij = numpy.where((abs(x) < tol) & (P != 0))[0]+1
Z[ij-1] = ij
P[ij-1] = numpy.zeros(max(ij.shape))
PP = numpy.where(P != 0)[0]+1
ZZ = numpy.where(Z != 0)[0]+1
CP[:, PP-1] = C[:, PP-1]
CP[:, ZZ-1] = numpy.zeros((m, msize(ZZ, 1)))
z=numpy.dot(numpy.linalg.pinv(CP), d)
z[ZZ-1] = numpy.zeros((msize(ZZ,1), msize(ZZ,0)))
x = z
resid = d - numpy.dot(C, x)
w = numpy.dot(C.T, resid)
return x, sum(resid * resid), resid