emwfnnls.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import numpy as np
  2. import time
  3. from numpy import float64, sum, nonzero, newaxis, finfo
  4. nu = newaxis
  5. def emwfnnls(data, G, F, r, Tmax):
  6. tol = 0
  7. delta_measure = 1
  8. em_iter_max = round(Tmax / delta_measure) + 1 #
  9. T = np.empty(shape=(em_iter_max + 1))
  10. T.fill(np.nan)
  11. RMSE = np.empty(shape=(2, em_iter_max + 1))
  12. RMSE.fill(np.nan)
  13. # RRE = np.empty(shape=(em_iter_max + 1))
  14. # RRE.fill(np.nan)
  15. np.put(F, data.idxOF, data.sparsePhi_F)
  16. np.put(G, data.idxOG, data.sparsePhi_G)
  17. X = data.X + np.multiply(data.nW, np.dot(G, F))
  18. GtX = np.dot(G.T, X)
  19. GtG = np.dot(G.T, G)
  20. # Iterative updating
  21. G = G.T
  22. k = 0
  23. RMSE[:, k] = np.linalg.norm(F[:, 0:-1] - data.F[:, 0:-1], 2, axis=1) / np.sqrt(F.shape[1] - 1)
  24. T[k] = 0
  25. t = time.time()
  26. # Main loop
  27. while time.time() - t <= Tmax + delta_measure:
  28. # Estimation step
  29. X = data.X + np.multiply(data.nW, np.dot(G.T, F))
  30. # Maximisation step
  31. # Optimize F with fixed G
  32. np.put(F, data.idxOF, 0)
  33. F, _ = fnnls(GtG, GtX - GtG.dot(data.Phi_F))
  34. np.put(F, data.idxOF, data.sparsePhi_F)
  35. FFt = np.dot(F, F.T)
  36. FXt = np.dot(F, X.T)
  37. # Optimize G with fixed F
  38. np.put(G.T, data.idxOG, 0)
  39. G, _ = fnnls(FFt, FXt - FFt.dot(data.Phi_G.T))
  40. np.put(G.T, data.idxOG, data.sparsePhi_G)
  41. GtG = np.dot(G, G.T)
  42. GtX = np.dot(G, X)
  43. if time.time() - t - k * delta_measure >= delta_measure:
  44. k = k + 1
  45. if k >= em_iter_max + 1:
  46. break
  47. RMSE[:, k] = np.linalg.norm(F[:, 0:-1] - data.F[:, 0:-1], 2, axis=1) / np.sqrt(F.shape[1] - 1)
  48. T[k] = time.time() - t
  49. # RRE[k] = nmf_norm_fro(data.Xtheo, G.T, F, data.W)
  50. # if k%100==0:
  51. # print(str(k)+' '+str(RMSE[0,k])+' '+str(RMSE[1,k]))
  52. # plt.semilogy(RRE)
  53. # plt.show()
  54. return {'RMSE': RMSE, 'T': T}
  55. def stop_rule(X, GradX):
  56. # Stopping Criterions
  57. pGrad = GradX[np.any(np.dstack((X > 0, GradX < 0)), 2)]
  58. return np.linalg.norm(pGrad, 2)
  59. # machine epsilon
  60. eps = finfo(float64).eps
  61. def any(a):
  62. # assuming a vector, a
  63. larger_than_zero = sum(a > 0)
  64. if larger_than_zero:
  65. return True
  66. else:
  67. return False
  68. def find_nonzero(a):
  69. # returns indices of nonzero elements in a
  70. return nonzero(a)[0]
  71. def fnnls(AtA, Aty, epsilon=None, iter_max=None):
  72. """
  73. Given a matrix A and vector y, find x which minimizes the objective function
  74. f(x) = ||Ax - y||^2.
  75. This algorithm is similar to the widespread Lawson-Hanson method, but
  76. implements the optimizations described in the paper
  77. "A Fast Non-Negativity-Constrained Least Squares Algorithm" by
  78. Rasmus Bro and Sumen De Jong.
  79. Note that the inputs are not A and y, but are
  80. A^T * A and A^T * y
  81. This is to avoid incurring the overhead of computing these products
  82. many times in cases where we need to call this routine many times.
  83. :param AtA: A^T * A. See above for definitions. If A is an (m x n)
  84. matrix, this should be an (n x n) matrix.
  85. :type AtA: numpy.ndarray
  86. :param Aty: A^T * y. See above for definitions. If A is an (m x n)
  87. matrix and y is an m dimensional vector, this should be an
  88. n dimensional vector.
  89. :type Aty: numpy.ndarray
  90. :param epsilon: Anything less than this value is consider 0 in the code.
  91. Use this to prevent issues with floating point precision.
  92. Defaults to the machine precision for doubles.
  93. :type epsilon: float
  94. :param iter_max: Maximum number of inner loop iterations. Defaults to
  95. 30 * [number of cols in A] (the same value that is used
  96. in the publication this algorithm comes from).
  97. :type iter_max: int, optional
  98. """
  99. if epsilon is None:
  100. epsilon = np.finfo(np.float64).eps
  101. n = AtA.shape[0]
  102. if iter_max is None:
  103. iter_max = 30 * n
  104. if Aty.ndim != 1 or Aty.shape[0] != n:
  105. raise ValueError('Invalid dimension; got Aty vector of size {}, ' \
  106. 'expected {}'.format(Aty.shape, n))
  107. # Represents passive and active sets.
  108. # If sets[j] is 0, then index j is in the active set (R in literature).
  109. # Else, it is in the passive set (P).
  110. sets = np.zeros(n, dtype=np.bool)
  111. # The set of all possible indices. Construct P, R by using `sets` as a mask
  112. ind = np.arange(n, dtype=int)
  113. P = ind[sets]
  114. R = ind[~sets]
  115. x = np.zeros(n, dtype=np.float64)
  116. w = Aty
  117. s = np.zeros(n, dtype=np.float64)
  118. i = 0
  119. # While R not empty and max_(n \in R) w_n > epsilon
  120. while not np.all(sets) and np.max(w[R]) > epsilon and i < iter_max:
  121. # Find index of maximum element of w which is in active set.
  122. j = np.argmax(w[R])
  123. # We have the index in MASKED w.
  124. # The real index is stored in the j-th position of R.
  125. m = R[j]
  126. # Move index from active set to passive set.
  127. sets[m] = True
  128. P = ind[sets]
  129. R = ind[~sets]
  130. # Get the rows, cols in AtA corresponding to P
  131. AtA_in_p = AtA[P][:, P]
  132. # Do the same for Aty
  133. Aty_in_p = Aty[P]
  134. # Update s. Solve (AtA)^p * s^p = (Aty)^p
  135. s[P] = np.linalg.lstsq(AtA_in_p, Aty_in_p, rcond=None)[0]
  136. s[R] = 0.
  137. while np.any(s[P] <= epsilon):
  138. i += 1
  139. mask = (s[P] <= epsilon)
  140. alpha = np.min(x[P][mask] / (x[P][mask] - s[P][mask]))
  141. x += alpha * (s - x)
  142. # Move all indices j in P such that x[j] = 0 to R
  143. # First get all indices where x == 0 in the MASKED x
  144. zero_mask = (x[P] < epsilon)
  145. # These correspond to indices in P
  146. zeros = P[zero_mask]
  147. # Finally, update the passive/active sets.
  148. sets[zeros] = False
  149. P = ind[sets]
  150. R = ind[~sets]
  151. # Get the rows, cols in AtA corresponding to P
  152. AtA_in_p = AtA[P][:, P]
  153. # Do the same for Aty
  154. Aty_in_p = Aty[P]
  155. # Update s. Solve (AtA)^p * s^p = (Aty)^p
  156. s[P] = np.linalg.lstsq(AtA_in_p, Aty_in_p, rcond=None)[0]
  157. s[R] = 0.
  158. x = s.copy()
  159. w = Aty - AtA.dot(x)
  160. return x