@@ -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 ()
0 commit comments