Skip to content

Commit ed68755

Browse files
authored
Merge pull request #17 from tensorly/issue15-fix-broken-tests
Fix core consistency test
2 parents 7513a27 + 151fa88 commit ed68755

File tree

2 files changed

+56
-8
lines changed

2 files changed

+56
-8
lines changed

tests/test_visualisation.py

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,64 @@ def test_core_element_plot_works_labelled_and_unlabelled(seed, labelled):
5353
assert isinstance(ax, matplotlib.axes.Axes)
5454

5555

56+
@pytest.mark.parametrize("weight_scale", [1, 100, 0.01])
5657
@pytest.mark.parametrize("normalised", [True, False])
57-
def test_core_element_plot_normalised_flag(seed, normalised):
58+
def test_core_element_has_correct_title(seed, normalised, weight_scale):
59+
"""This test checks that the title of the core element plot is correct.
60+
61+
There are six scenarios to test (CC=Core consistency):
62+
63+
1. CC = 100, normalised=True
64+
2. CC = 100, normalised=False
65+
3. 0 <= CC < 100, normalised=True
66+
4. 0 <= CC < 100, normalised=False
67+
5. CC < 0, normalised=True
68+
6. CC < 0, normalised=False
69+
70+
To test both scenarios when CC = 100, we have a noise-free dataset and the correct
71+
decomposition.
72+
73+
To test scenario 3, we need that :math:`0 < \|G - T\| \leq \|G\|`. To accomplish this, can
74+
have large entries in :math:`G` that point in the "same direction" as :math:`T`. Similarly, to
75+
test scenario 4, we need that :math:`0 < \|G - T\| \geq R`, which we can accomplish by having
76+
small entries in :math:`G` that point in the "same direction" as :math:`T`.
77+
78+
To test scenario 5, we need that :math:`\|G - T\| > \|G\|`, which we can accomplish by having
79+
small entries in :math:`G`. To test scenario 6, we need that :math:`\|G - T\| > R`, which we
80+
can accomplish by having large entries in :math:`G`.
81+
82+
We can, in other words, create decompositions that cover all 6 above scenarios so long as we
83+
can create decompositions whose optimal core tensor "points in the same direction" as the
84+
superdiagonal tensor consisting only ones and whose optimal core tensor's magnitude we can
85+
control. Luckily, we can control this by only scaling the weights by positive number. Then,
86+
the optimal core tensor will be a superdiagonal tensor whose elements are the reciprocal of
87+
the scaling coefficient.
88+
"""
5889
rank = 3
59-
cp_tensor, X = simulated_random_cp_tensor((10, 20, 30), rank, noise_level=0.2, seed=seed)
60-
# If not normalised
90+
cp_tensor, X = simulated_random_cp_tensor((10, 20, 30), rank, noise_level=0.0, seed=seed)
91+
cp_tensor[0][:] *= weight_scale
92+
6193
ax = visualisation.core_element_plot(cp_tensor, X, normalised=normalised)
6294
title = ax.get_title()
63-
title_core_consistency = float(title.split(": ")[1])
6495
core_consistency = model_evaluation.core_consistency(cp_tensor, X, normalised=normalised)
65-
assert title_core_consistency == pytest.approx(core_consistency, abs=0.1)
96+
97+
# Case 5 and 6, respectively:
98+
if (weight_scale > 1 and normalised) or (weight_scale < 1 and not normalised):
99+
assert title.split(": ")[1] == "<0"
100+
else:
101+
title_core_consistency = float(title.split(": ")[1])
102+
assert title_core_consistency == pytest.approx(core_consistency, abs=0.1)
103+
104+
105+
@pytest.mark.parametrize("weight_scale", [1, 100, 0.01])
106+
@pytest.mark.parametrize("normalised", [True, False])
107+
def test_core_element_has_core_element_scatter_points(seed, normalised, weight_scale):
108+
rank = 3
109+
cp_tensor, X = simulated_random_cp_tensor((10, 20, 30), rank, noise_level=0.1, seed=seed)
110+
cp_tensor[0][:] *= weight_scale
111+
112+
ax = visualisation.core_element_plot(cp_tensor, X, normalised=normalised)
113+
core_consistency = model_evaluation.core_consistency(cp_tensor, X, normalised=normalised)
66114

67115
superdiag_x, superdiag_y = ax.lines[-2].get_data()
68116
offdiag_x, offdiag_y = ax.lines[-1].get_data()

tlviz/model_evaluation.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,15 +334,15 @@ def predictive_power(cp_tensor, y, sklearn_estimator, mode=0, metric=None, axis=
334334
>>> from tlviz.data import simulated_random_cp_tensor
335335
>>> import numpy as np
336336
>>> rng = np.random.default_rng(0)
337-
>>> cp_tensor, X = simulated_random_cp_tensor((30, 10, 10), 5, noise_level=0.3, seed=rng)
337+
>>> cp_tensor, X = simulated_random_cp_tensor((30, 10, 10), 3, noise_level=0.1, seed=rng)
338338
>>> weights, (A, B, C) = cp_tensor
339-
>>> regression_coefficients = rng.standard_normal((5, 1))
339+
>>> regression_coefficients = rng.standard_normal((3, 1))
340340
>>> Y = A @ regression_coefficients
341341
342342
Next, we fit a PARAFAC model to this data
343343
344344
>>> from tensorly.decomposition import parafac
345-
>>> est_cp_tensor = parafac(X, 5)
345+
>>> est_cp_tensor = parafac(X, 3)
346346
347347
Finally, we see how well the estimated decomposition can describe our target variable, ``Y``.
348348
This will use the :math:`R^2`-coefficient for scoring, as that is the default scoring method

0 commit comments

Comments
 (0)