Skip to content

Commit 16db3e1

Browse files
committed
Fix error messages in convexity and add relevant tests
1 parent 6068c50 commit 16db3e1

File tree

2 files changed

+141
-45
lines changed

2 files changed

+141
-45
lines changed

src/eff_conv/convexity.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import numpy as np
66

7+
from eff_conv.ib.utils import IB_EPSILON
8+
79

810
class SimilaritySpace:
911
"""A similarity space contains points (which should correspond in order to referents or meanings) and the priors upon those points.
@@ -29,6 +31,10 @@ def __init__(self, sim_space: np.ndarray, point_prior: np.ndarray = None):
2931
or point_prior.shape[0] != sim_space.shape[0]
3032
):
3133
raise ValueError("Point priors not of correct size")
34+
if np.abs(np.sum(point_prior) - 1) > IB_EPSILON:
35+
raise ValueError("Point priors must sum to 1")
36+
if (point_prior <= 0).any():
37+
raise ValueError("Prior values must be greater than 0")
3238
self.point_prior = point_prior
3339
else:
3440
self.point_prior = np.array(
@@ -65,6 +71,10 @@ def quasi_convexity(self, point_dist: np.ndarray, steps: int) -> float:
6571
raise ValueError("Quasi-Convexity input must be a probability distribution")
6672
if np.size(point_dist) != self.sim_space.shape[0]:
6773
raise ValueError("Quasi-Convexity input must map to all points")
74+
if np.abs(np.sum(point_dist) - 1) > IB_EPSILON:
75+
raise ValueError("Quasi-Convexity input must sum to 1")
76+
if (point_dist < 0).any():
77+
raise ValueError("Quasi-Convexity input must be greater than or equal to 0")
6878
if steps <= 0:
6979
raise ValueError("Steps must be positive")
7080

@@ -132,6 +142,11 @@ def skinner_encoder_convexity(
132142
float: The quasi-convexity of the matrix.
133143
"""
134144

145+
if np.abs(np.sum(prior) - 1) > IB_EPSILON:
146+
raise ValueError("Prior must sum to 1")
147+
if (prior <= 0).any():
148+
raise ValueError("Prior must be greater than 0")
149+
135150
# Apply Bayes' rule
136151
reconstructed = distrubitions.T * prior[:, None] / self.point_prior
137152
maximums = np.max(reconstructed, axis=0)
@@ -163,6 +178,11 @@ def encoder_convexity(
163178
float: The quasi-convexity of the matrix.
164179
"""
165180

181+
if np.abs(np.sum(prior) - 1) > IB_EPSILON:
182+
raise ValueError("Prior must sum to 1")
183+
if (prior <= 0).any():
184+
raise ValueError("Prior must be greater than 0")
185+
166186
convexities = []
167187
for word in distrubitions.T:
168188
convexities.append(self.quasi_convexity(word, steps))

src/tests/test_convexity.py

Lines changed: 121 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import numpy as np
2+
import pytest
23

34
from eff_conv.convexity import SimilaritySpace
45
from eff_conv.ib.language import IBLanguage
@@ -32,17 +33,44 @@ class TestConvexity:
3233
)
3334

3435
# Tests for convexity.py
36+
def test_similarity_space_check(self):
37+
with pytest.raises(ValueError):
38+
space_wrong_shape = SimilaritySpace(np.array([1]))
39+
with pytest.raises(ValueError):
40+
space_wrong_prior_len = SimilaritySpace(
41+
np.array([[1]]), point_prior=np.array([1, 2])
42+
)
43+
with pytest.raises(ValueError):
44+
space_wrong_prior_shape = SimilaritySpace(
45+
np.array([[1]]), point_prior=np.array([[1]])
46+
)
47+
with pytest.raises(ValueError):
48+
space_invalid_prior = SimilaritySpace(
49+
np.array([[1], [2]]), point_prior=np.array([1, 2])
50+
)
51+
with pytest.raises(ValueError):
52+
space_zero_prior = SimilaritySpace(
53+
np.array([[1], [2]]), point_prior=np.array([1, 0])
54+
)
55+
with pytest.raises(ValueError):
56+
space_negative_prior = SimilaritySpace(
57+
np.array([[1], [2]]), point_prior=np.array([2, -1])
58+
)
59+
3560
def test_convexity_calculation(self):
3661
assert (
37-
self.sim_space.encoder_convexity(np.ones((9, 1)) / 9, np.array([1])) - 1
62+
abs(
63+
self.sim_space.encoder_convexity(np.ones((9, 1)) / 9, np.array([1])) - 1
64+
)
3865
< IB_EPSILON
3966
)
4067
# Epsilon is higher because rounding errors are more common beacuse of the nature of the algorithm
4168
assert (
42-
self.sim_space.skinner_encoder_convexity(
43-
np.array(
44-
[
45-
# fmt: off
69+
abs(
70+
self.sim_space.skinner_encoder_convexity(
71+
np.array(
72+
[
73+
# fmt: off
4674
[0.2, 0],
4775
[0, 1],
4876
[0.2, 0],
@@ -52,19 +80,21 @@ def test_convexity_calculation(self):
5280
[0.2, 0],
5381
[0, 0],
5482
[0.2, 0],
55-
# fmt: on
56-
]
57-
),
58-
np.array([0.5, 0.5]),
83+
# fmt: on
84+
]
85+
),
86+
np.array([0.5, 0.5]),
87+
)
88+
- 19 / 27
5989
)
60-
- 19 / 27
6190
< 0.005
6291
)
6392
assert (
64-
self.sim_space.encoder_convexity(
65-
np.array(
66-
[
67-
# fmt: off
93+
abs(
94+
self.sim_space.encoder_convexity(
95+
np.array(
96+
[
97+
# fmt: off
6898
[0.2, 0],
6999
[0, 1],
70100
[0.2, 0],
@@ -74,50 +104,56 @@ def test_convexity_calculation(self):
74104
[0.2, 0],
75105
[0, 0],
76106
[0.2, 0],
77-
# fmt: on
78-
]
79-
),
80-
np.array([0.5, 0.5]),
107+
# fmt: on
108+
]
109+
),
110+
np.array([0.5, 0.5]),
111+
)
112+
- 14 / 18
81113
)
82-
- 14 / 18
83114
< 0.005
84115
)
85116

86117
def test_projection_down(self):
87118
# This also tests 1d spaces
88119
assert (
89-
self.sim_space_large.encoder_convexity(
90-
np.array(
91-
[
92-
# fmt: off
120+
abs(
121+
self.sim_space_large.encoder_convexity(
122+
np.array(
123+
[
124+
# fmt: off
93125
[0.33], [0], [0], [0],
94126
[0], [0], [0], [0],
95127
[0.33], [0], [0], [0],
96128
[0.33], [0], [0], [0],
97-
# fmt: on
98-
]
99-
),
100-
np.array([1]),
129+
# fmt: on
130+
]
131+
)
132+
/ 0.99,
133+
np.array([1]),
134+
)
135+
- 3 / 4
101136
)
102-
- 3 / 4
103137
< 0.005
104138
)
105139
assert (
106-
self.sim_space_large.encoder_convexity(
107-
np.array(
108-
[
109-
# fmt: off
140+
abs(
141+
self.sim_space_large.encoder_convexity(
142+
np.array(
143+
[
144+
# fmt: off
110145
[0.5], [0], [0], [0],
111146
[0], [0], [0], [0],
112147
[0], [0], [0], [0],
113148
[0.5], [0], [0], [0],
114-
# fmt: on
115-
]
116-
),
117-
np.array([1]),
118-
steps=1000,
149+
# fmt: on
150+
]
151+
),
152+
np.array([1]),
153+
steps=1000,
154+
)
155+
- 1 / 2
119156
)
120-
- 1 / 2
121157
< 0.005
122158
)
123159

@@ -132,17 +168,57 @@ def test_language_convexity(self):
132168
)
133169
simple_lang = IBLanguage(simple_struct, np.ones((1, 9)))
134170
assert (
135-
self.sim_space.language_convexity(simple_lang)
136-
- self.sim_space.encoder_convexity(np.ones((9, 1)) / 9, np.array([1]))
171+
abs(
172+
self.sim_space.language_convexity(simple_lang)
173+
- self.sim_space.encoder_convexity(np.ones((9, 1)) / 9, np.array([1]))
174+
)
137175
< IB_EPSILON
138176
)
139177
# This will fail on remote if the epsilon is not higher
140178
assert (
141-
self.sim_space.language_convexity(simple_lang, referents=True, steps=1000)
142-
- self.sim_space.encoder_convexity(
143-
np.array([[0.465, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.465]]).T,
144-
np.array([1]),
145-
steps=1000,
179+
abs(
180+
self.sim_space.language_convexity(
181+
simple_lang, referents=True, steps=1000
182+
)
183+
- self.sim_space.encoder_convexity(
184+
np.array(
185+
[[0.465, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.465]]
186+
).T,
187+
np.array([1]),
188+
steps=1000,
189+
)
146190
)
147191
< 0.005
148192
)
193+
194+
def test_convexity_check(self):
195+
with pytest.raises(ValueError):
196+
input_wrong_shape = self.sim_space.quasi_convexity(np.ones((9, 1)), 100)
197+
with pytest.raises(ValueError):
198+
input_wrong_size = self.sim_space.quasi_convexity(np.ones(8) / 8, 100)
199+
with pytest.raises(ValueError):
200+
input_invalid = self.sim_space.quasi_convexity(np.ones(9), 100)
201+
with pytest.raises(ValueError):
202+
input_negative = self.sim_space.quasi_convexity(
203+
np.array([-7, 1, 1, 1, 1, 1, 1, 1, 1, 1]), 100
204+
)
205+
with pytest.raises(ValueError):
206+
steps_negative = self.sim_space.quasi_convexity(np.ones(9) / 9, -1)
207+
208+
def test_encoder_check(self):
209+
with pytest.raises(ValueError):
210+
prior_invalid = self.sim_space.encoder_convexity(
211+
np.ones((9, 1)) / 9, np.array([0.9])
212+
)
213+
with pytest.raises(ValueError):
214+
prior_invalid_skinner = self.sim_space.skinner_encoder_convexity(
215+
np.ones((9, 1)) / 9, np.array([0.9])
216+
)
217+
with pytest.raises(ValueError):
218+
prior_negative = self.sim_space.encoder_convexity(
219+
np.ones((9, 2)) / 9, np.array([-1, 2])
220+
)
221+
with pytest.raises(ValueError):
222+
prior_negative_skinner = self.sim_space.skinner_encoder_convexity(
223+
np.ones((9, 2)) / 9, np.array([-1, 2])
224+
)

0 commit comments

Comments
 (0)