|
26 | 26 | from numpy import array, dot, ones, sqrt |
27 | 27 | from scipy.linalg import pinv |
28 | 28 | from numpy.random import rand |
29 | | -from .core import nvecs, norm |
| 29 | +from .core import nvecs, norm, khatrirao |
30 | 30 | from .ktensor import ktensor |
31 | 31 |
|
32 | 32 | _log = logging.getLogger('CP') |
@@ -171,6 +171,72 @@ def als(X, rank, **kwargs): |
171 | 171 | return P, fit, itr, array(exectimes) |
172 | 172 |
|
173 | 173 |
|
| 174 | +def apr(X, r, M=None, outer_iter=100, inner_iter=10, t=1e-4, k=0.01, |
| 175 | + k_tol=1e-10, e=1e-10): |
| 176 | + """ |
| 177 | + Alternating Poisson Regression algorithm to compute the CP decomposition. |
| 178 | +
|
| 179 | + Parameters |
| 180 | + ---------- |
| 181 | + X : tensor |
| 182 | + The tensor to be decomposed. |
| 183 | + r : Number of R components. |
| 184 | + M : Initial guess for tensor decomposed components. |
| 185 | + outer_iter : Number of maximum outer iterations. |
| 186 | + inner_iter : Number of maximum inner iterations. |
| 187 | + t : Convergence tolerance of KKT conditions. |
| 188 | + k : Inadmissible zero avoidance adjustment. |
| 189 | + k_tol : Tolerance of identifying a potentional inadmissible zero. |
| 190 | + e : Minimum divisor to prevent divide-by-zero. |
| 191 | +
|
| 192 | + Returns |
| 193 | + ------- |
| 194 | + M : ktensor |
| 195 | + Rank ``rank`` factorization of X. ``M.U[i]`` corresponds to the factor |
| 196 | + matrix for the i-th mode. ``M.lambda[i]`` corresponds to the weight |
| 197 | + of the i-th mode. |
| 198 | + i : int |
| 199 | + Number of iterations that were needed until convergence |
| 200 | + exectimes : ndarray of floats |
| 201 | + Time needed for each single iteration |
| 202 | + References |
| 203 | + ---------- |
| 204 | + .. [1] EC Chi, TG Kolda. |
| 205 | + On Tensors, Sparsity, and Nonnegative Factorizations. |
| 206 | + SIAM Journal on Matrix Analysis and Applications, (2012). |
| 207 | + """ |
| 208 | + N = len(X.shape) |
| 209 | + if M is None: |
| 210 | + M = ktensor([np.random.rand(X.shape[i], r) for i in range(N)]) |
| 211 | + phi = np.empty([N, ], dtype=object) |
| 212 | + |
| 213 | + exectimes = [] |
| 214 | + for i in range(outer_iter): |
| 215 | + tic = time.clock() |
| 216 | + is_converged = True |
| 217 | + for n in range(N): |
| 218 | + S = np.zeros((X.shape[n], r)) |
| 219 | + if i > 0: |
| 220 | + S[(phi[n] > 1) & (M.U[n] < k_tol)] = k |
| 221 | + b = np.dot((M.U[n] + S), np.diag(M.lmbda)) |
| 222 | + pi = khatrirao(tuple( |
| 223 | + [M.U[i] for i in range(n) + range(n + 1, N)])).transpose() |
| 224 | + for j in range(inner_iter): |
| 225 | + phi[n] = np.dot(X.unfold(n) / np.maximum(np.dot(b, pi), e), |
| 226 | + pi.transpose()) |
| 227 | + if np.amax(np.abs(np.ravel(np.minimum(M.U[n], 1-phi[n])))) < t: |
| 228 | + break |
| 229 | + |
| 230 | + is_converged = False |
| 231 | + b *= phi[n] |
| 232 | + M.lmbda = np.dot(np.ones(b.shape[0]).transpose(), b) |
| 233 | + M.U[n] = np.dot(b, np.linalg.inv(np.diag(M.lmbda))) |
| 234 | + exectimes.append(time.clock() - tic) |
| 235 | + if is_converged: |
| 236 | + break |
| 237 | + return M, i, exectimes |
| 238 | + |
| 239 | + |
174 | 240 | def opt(X, rank, **kwargs): |
175 | 241 | ainit = kwargs.pop('init', _DEF_INIT) |
176 | 242 | maxiter = kwargs.pop('maxIter', _DEF_MAXITER) |
|
0 commit comments