Skip to content

Commit 6f7a55f

Browse files
committed
Implementation of CP-APR algorithm
https://arxiv.org/pdf/1112.2414.pdf
1 parent fe517e9 commit 6f7a55f

1 file changed

Lines changed: 67 additions & 1 deletion

File tree

sktensor/cp.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from numpy import array, dot, ones, sqrt
2727
from scipy.linalg import pinv
2828
from numpy.random import rand
29-
from .core import nvecs, norm
29+
from .core import nvecs, norm, khatrirao
3030
from .ktensor import ktensor
3131

3232
_log = logging.getLogger('CP')
@@ -171,6 +171,72 @@ def als(X, rank, **kwargs):
171171
return P, fit, itr, array(exectimes)
172172

173173

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+
174240
def opt(X, rank, **kwargs):
175241
ainit = kwargs.pop('init', _DEF_INIT)
176242
maxiter = kwargs.pop('maxIter', _DEF_MAXITER)

0 commit comments

Comments
 (0)