Skip to content

Commit 27dbeeb

Browse files
committed
CP_APR: Add tests fpr sptensor, and corresponding bug fixes to improve test coverage.
1 parent 6e0e3b1 commit 27dbeeb

File tree

2 files changed

+69
-8
lines changed

2 files changed

+69
-8
lines changed

pyttb/cp_apr.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def cp_apr(tensor, rank, algorithm='mu', stoptol=1e-4, stoptime=1e6, maxiters=10
1515
kappa=0.01, kappatol=1e-10, epsActive=1e-8, mu0=1e-5, precompinds=True, inexact=True,
1616
lbfgsMem=3):
1717
"""
18-
Compute nonnegative CP with alternating Poisson regression.
18+
Compute non-negative CP with alternating Poisson regression.
1919
2020
Parameters
2121
----------
@@ -376,9 +376,10 @@ def tt_cp_apr_pdnr(tensor, rank, init, stoptol, stoptime, maxiters, maxinneriter
376376
sparseIx = []
377377
for n in range(N):
378378
num_rows = M[n].shape[0]
379-
sparseIx.append(np.zeros((num_rows, 1)))
379+
row_indices = []
380380
for jj in range(num_rows):
381-
sparseIx[n][jj] = np.where(tensor.subs[:, n] == jj)[0]
381+
row_indices.append(np.where(tensor.subs[:, n] == jj)[0])
382+
sparseIx.append(row_indices)
382383

383384
if printitn > 0:
384385
print('done\n')
@@ -426,7 +427,7 @@ def tt_cp_apr_pdnr(tensor, rank, init, stoptol, stoptime, maxiters, maxinneriter
426427
M.factor_matrices[n][jj, :] = 0
427428
continue
428429

429-
x_row = tensor.vals(sparse_indices)
430+
x_row = tensor.vals[sparse_indices]
430431

431432
# Calculate just the columns of Pi needed for this row.
432433
Pi = ttb.tt_calcpi_prowsubprob(tensor, M, rank, n, N, isSparse, sparse_indices)
@@ -683,9 +684,10 @@ def tt_cp_apr_pqnr(tensor, rank, init, stoptol, stoptime, maxiters, maxinneriter
683684
sparseIx = []
684685
for n in range(N):
685686
num_rows = M[n].shape[0]
686-
sparseIx.append(np.zeros((num_rows, 1)))
687+
row_indices = []
687688
for jj in range(num_rows):
688-
sparseIx[n][jj] = np.where(tensor.subs[:, n] == jj)[0]
689+
row_indices.append(np.where(tensor.subs[:, n] == jj)[0])
690+
sparseIx.append(row_indices)
689691

690692
if printitn > 0:
691693
print('done\n')
@@ -726,7 +728,7 @@ def tt_cp_apr_pqnr(tensor, rank, init, stoptol, stoptime, maxiters, maxinneriter
726728
M.factor_matrices[n][jj, :] = 0
727729
continue
728730

729-
x_row = tensor.vals(sparse_indices)
731+
x_row = tensor.vals[sparse_indices]
730732

731733
# Calculate just the columns of Pi needed for this row.
732734
Pi = ttb.tt_calcpi_prowsubprob(tensor, M, rank, n, N, isSparse, sparse_indices)
@@ -1227,7 +1229,7 @@ def tt_loglikelihood_row(isSparse, data_row, model_row, Pi):
12271229
"""
12281230
term1 = -np.sum(model_row)
12291231
if isSparse:
1230-
term2 = np.sum(data_row.transpose() * np.log(model_row.dot(Pi)))
1232+
term2 = np.sum(data_row.transpose() * np.log(model_row.dot(Pi.transpose())))
12311233
else:
12321234
b_pi = model_row.dot(Pi.transpose())
12331235
term2 = 0

tests/test_cp_apr.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ def test_cpapr_mu(capsys):
125125
capsys.readouterr()
126126
assert output['nTotalIters'] == 2
127127

128+
# Edge cases
129+
# Confirm timeout works
130+
non_correct_answer = ktensorInstance*2
131+
_ = ttb.cp_apr(tensorInstance, 2, init=non_correct_answer, stoptime=-1)
132+
out, _ = capsys.readouterr()
133+
assert "time limit exceeded" in out
134+
128135
@pytest.mark.indevelopment
129136
def test_cpapr_pdnr(capsys):
130137
# Test simple case
@@ -139,6 +146,23 @@ def test_cpapr_pdnr(capsys):
139146
capsys.readouterr()
140147
assert np.isclose(M.full().data, ktensorInstance.full().data, rtol=1e-04).all()
141148

149+
# Try solve with sptensor
150+
sptensorInstance = ttb.sptensor.from_tensor_type(tensorInstance)
151+
np.random.seed(123)
152+
M, _, _ = ttb.cp_apr(sptensorInstance, 2, algorithm="pdnr")
153+
capsys.readouterr()
154+
assert np.isclose(M.full().data, ktensorInstance.full().data, rtol=1e-04).all()
155+
M, _, _ = ttb.cp_apr(sptensorInstance, 2, algorithm="pdnr", precompinds=False)
156+
capsys.readouterr()
157+
assert np.isclose(M.full().data, ktensorInstance.full().data, rtol=1e-04).all()
158+
159+
# Edge cases
160+
# Confirm timeout works
161+
non_correct_answer = ktensorInstance*2
162+
_ = ttb.cp_apr(tensorInstance, 2, init=non_correct_answer, algorithm="pdnr", stoptime=-1)
163+
out, _ = capsys.readouterr()
164+
assert "time limit exceeded" in out
165+
142166
@pytest.mark.indevelopment
143167
def test_cpapr_pqnr(capsys):
144168
# Test simple case
@@ -165,6 +189,22 @@ def test_cpapr_pqnr(capsys):
165189
capsys.readouterr()
166190
assert np.isclose(M.full().data, ktensorInstance.full().data, rtol=1e-01).all()
167191

192+
# Try solve with sptensor
193+
sptensorInstance = ttb.sptensor.from_tensor_type(tensorInstance)
194+
np.random.seed(123)
195+
M, _, _ = ttb.cp_apr(sptensorInstance, 2, algorithm="pqnr")
196+
capsys.readouterr()
197+
assert np.isclose(M.full().data, ktensorInstance.full().data, rtol=1e-01).all()
198+
M, _, _ = ttb.cp_apr(sptensorInstance, 2, algorithm="pqnr", precompinds=False)
199+
capsys.readouterr()
200+
assert np.isclose(M.full().data, ktensorInstance.full().data, rtol=1e-01).all()
201+
202+
# Edge cases
203+
# Confirm timeout works
204+
_ = ttb.cp_apr(tensorInstance, 2, algorithm="pqnr", stoptime=-1)
205+
out, _ = capsys.readouterr()
206+
assert "time limit exceeded" in out
207+
168208

169209
# PDNR tests below
170210
@pytest.mark.indevelopment
@@ -367,3 +407,22 @@ def test_getSearchDirPqnr():
367407
search, pred = ttb.getSearchDirPqnr(model_row, phi, 1e-6, delta_model, delta_grad, phi, 1, 5, False)
368408
# This only verifies that for the right shaped input nothing crashes. Doesn't verify correctness
369409
assert True
410+
411+
def test_cp_apr_negative_tests():
412+
dense_tensor = ttb.tensor.from_data(np.ones((2, 2, 2)))
413+
bad_weights = np.array([8.])
414+
bad_factors = [np.array([[1.]])] * 3
415+
bad_initial_guess_shape = ttb.ktensor.from_data(bad_weights, bad_factors)
416+
with pytest.raises(AssertionError):
417+
ttb.cp_apr(dense_tensor, init=bad_initial_guess_shape, rank=1)
418+
good_weights = np.array([8.] * 3)
419+
good_factor = np.array([[1., 1., 1.], [1., 1., 1.]])
420+
bad_initial_guess_factors = ttb.ktensor.from_data(good_weights, [-1. * good_factor] * 3)
421+
with pytest.raises(AssertionError):
422+
ttb.cp_apr(dense_tensor, init=bad_initial_guess_factors, rank=3)
423+
bad_initial_guess_weight = ttb.ktensor.from_data(-1. * good_weights, [good_factor] * 3)
424+
with pytest.raises(AssertionError):
425+
ttb.cp_apr(dense_tensor, init=bad_initial_guess_weight, rank=3)
426+
427+
with pytest.raises(AssertionError):
428+
ttb.cp_apr(dense_tensor, rank=1, algorithm='UNSUPPORTED_ALG')

0 commit comments

Comments
 (0)