@@ -248,32 +248,28 @@ def test_score_standard_parametrization(self):
248248 """Test SCORE for standard parametrization against analytical formula."""
249249 a , b = 2.0 , 5.0
250250 dist = self .uniform_family (lower_bound = a , upper_bound = b )
251- x = np .array ([1.0 , 2.0 , 3.5 , 5.0 , 6 .0 ])
251+ x = np .array ([2.0 , 3.5 , 5.0 ])
252252 grad = dist .family .score (dist .parametrization , x )
253253
254254 width = b - a
255- inside = (x >= a ) & (x <= b )
256- expected = np .stack (
257- [np .where (inside , 1.0 / width , 0.0 ), np .where (inside , - 1.0 / width , 0.0 )], axis = - 1
258- )
255+ expected = np .tile ([1.0 / width , - 1.0 / width ], (len (x ), 1 ))
259256
260257 np .testing .assert_allclose (grad , expected , rtol = self .CALCULATION_PRECISION )
261258
262259 def test_score_meanWidth_parametrization (self ):
263260 """Test SCORE for meanWidth parametrization via chain rule."""
264261 mean , width = 3.5 , 3.0 # corresponds to a=2, b=5
265262 dist = self .uniform_family (parametrization_name = "meanWidth" , mean = mean , width = width )
266- x = np .array ([1.0 , 2.0 , 3.5 , 5.0 , 6 .0 ])
263+ x = np .array ([2.0 , 3.5 , 5.0 ])
267264 grad = dist .family .score (dist .parametrization , x )
268265
269- a , b = 2.0 , 5.0
270- inside = (x >= a ) & (x <= b )
271- base_grad_a = np .where (inside , 1.0 / 3.0 , 0.0 )
272- base_grad_b = np .where (inside , - 1.0 / 3.0 , 0.0 )
266+ _a , _b = 2.0 , 5.0
267+ base_grad_a = 1.0 / 3.0
268+ base_grad_b = - 1.0 / 3.0
273269 # Transform to (mean, width)
274270 expected_mean = 0.5 * (base_grad_a + base_grad_b )
275271 expected_width = - base_grad_a + base_grad_b
276- expected = np .stack ([expected_mean , expected_width ], axis = - 1 )
272+ expected = np .tile ([expected_mean , expected_width ], ( len ( x ), 1 ) )
277273
278274 np .testing .assert_allclose (grad , expected , rtol = self .CALCULATION_PRECISION )
279275
@@ -283,17 +279,16 @@ def test_score_minRange_parametrization(self):
283279 dist = self .uniform_family (
284280 parametrization_name = "minRange" , minimum = minimum , range_val = range_val
285281 )
286- x = np .array ([1.0 , 2.0 , 3.5 , 5.0 , 6 .0 ])
282+ x = np .array ([2.0 , 3.5 , 5.0 ])
287283 grad = dist .family .score (dist .parametrization , x )
288284
289- a , b = 2.0 , 5.0
290- inside = (x >= a ) & (x <= b )
291- base_grad_a = np .where (inside , 1.0 / 3.0 , 0.0 )
292- base_grad_b = np .where (inside , - 1.0 / 3.0 , 0.0 )
285+ _a , _b = 2.0 , 5.0
286+ base_grad_a = 1.0 / 3.0
287+ base_grad_b = - 1.0 / 3.0
293288 # Transform to (minimum, range_val)
294289 expected_min = base_grad_a
295290 expected_range = - base_grad_a + base_grad_b
296- expected = np .stack ([expected_min , expected_range ], axis = - 1 )
291+ expected = np .tile ([expected_min , expected_range ], ( len ( x ), 1 ) )
297292
298293 np .testing .assert_allclose (grad , expected , rtol = self .CALCULATION_PRECISION )
299294
@@ -317,6 +312,17 @@ def logpdf_b(b_val: float) -> float:
317312 np .testing .assert_allclose (grad [0 , 0 ], grad_a_num , rtol = 1e-5 )
318313 np .testing .assert_allclose (grad [0 , 1 ], grad_b_num , rtol = 1e-5 )
319314
315+ def test_score_with_integer_x (self ):
316+ """Test that SCORE returns float gradient even for integer x."""
317+ a , b = 2.0 , 5.0
318+ dist = self .uniform_family (lower_bound = a , upper_bound = b )
319+ x_int = np .array ([2 , 3 , 4 , 5 ], dtype = int )
320+ grad = dist .family .score (dist .parametrization , x_int )
321+ assert grad .dtype == np .float64
322+ width = b - a
323+ expected = np .full ((len (x_int ), 2 ), [1.0 / width , - 1.0 / width ], dtype = np .float64 )
324+ np .testing .assert_allclose (grad , expected , rtol = self .CALCULATION_PRECISION )
325+
320326 @pytest .mark .parametrize (
321327 "parametrization_name, params" ,
322328 [
@@ -327,12 +333,27 @@ def logpdf_b(b_val: float) -> float:
327333 )
328334 def test_score_shape (self , parametrization_name , params ):
329335 """Test SCORE shape for all uniform parametrizations."""
330- x = np .array ([1.0 , 2.0 , 3.5 , 5.0 , 6 .0 ])
336+ x = np .array ([2.0 , 3.5 , 5.0 ])
331337 dist = self .uniform_family (parametrization_name = parametrization_name , ** params )
332338 grad = dist .family .score (dist .parametrization , x )
333339 assert grad .shape == (len (x ), 2 )
334340 assert grad .dtype == float
335341
342+ @pytest .mark .parametrize ("bad_x" , [np .inf , - np .inf , np .nan ])
343+ def test_score_raises_for_nonfinite_x (self , bad_x ):
344+ """Test that SCORE raises ValueError for non-finite x (inf, nan)."""
345+ a , b = 2.0 , 5.0
346+ dist = self .uniform_family (lower_bound = a , upper_bound = b )
347+ with pytest .raises (ValueError , match = "Score is undefined for non‑finite x" ):
348+ dist .family .score (dist .parametrization , np .array ([bad_x ]))
349+
350+ def test_score_raises_for_x_outside_support (self ):
351+ a , b = 2.0 , 5.0
352+ dist = self .uniform_family (lower_bound = a , upper_bound = b )
353+ x_bad = np .array ([1.0 , 6.0 ])
354+ with pytest .raises (ValueError , match = "Score is undefined for x outside support" ):
355+ dist .family .score (dist .parametrization , x_bad )
356+
336357
337358class TestUniformFamilyEdgeCases (BaseDistributionTest ):
338359 """Test edge cases and error conditions for uniform distribution."""
0 commit comments