@@ -2189,19 +2189,43 @@ def test_multinomial(self, n):
2189
2189
lambda value , n , p : scipy .stats .multinomial .logpmf (value , n , p ),
2190
2190
)
2191
2191
2192
- def test_multinomial_invalid (self ):
2193
- # Test non-scalar invalid parameters/values
2194
- value = np .array ([[1 , 2 , 2 ], [4 , 0 , 1 ]])
2192
+ def test_multinomial_invalid_value (self ):
2193
+ # Test passing non-scalar invalid parameters/values to an otherwise valid Multinomial,
2194
+ # evaluates to -inf
2195
+ value = np .array ([[1 , 2 , 2 ], [3 , - 1 , 0 ]])
2196
+ valid_dist = Multinomial .dist (n = 5 , p = np .ones (3 ) / 3 )
2197
+ assert np .all (np .isfinite (pm .logp (valid_dist , value ).eval ()) == np .array ([True , False ]))
2195
2198
2196
- invalid_dist = Multinomial .dist (n = 5 , p = [- 1 , 1 , 1 ], size = 2 )
2197
- # TODO: Multinomial normalizes p, so it is impossible to trigger p checks
2198
- # with pytest.raises(ParameterValueError):
2199
- with does_not_raise ():
2199
+ def test_multinomial_negative_p (self ):
2200
+ # test passing a list/numpy with negative p raises an immediate error
2201
+ with pytest .raises (ValueError , match = "[-1, 1, 1]" ):
2202
+ with Model () as model :
2203
+ x = Multinomial ("x" , n = 5 , p = [- 1 , 1 , 1 ])
2204
+
2205
+ def test_multinomial_p_not_normalized (self ):
2206
+ # test UserWarning is raised for p vals that sum to more than 1
2207
+ # and normaliation is triggered
2208
+ with pytest .warns (UserWarning , match = "[5]" ):
2209
+ with pm .Model () as m :
2210
+ x = pm .Multinomial ("x" , n = 5 , p = [1 , 1 , 1 , 1 , 1 ])
2211
+ # test stored p-vals have been normalised
2212
+ assert np .isclose (m .x .owner .inputs [4 ].sum ().eval (), 1.0 )
2213
+
2214
+ def test_multinomial_negative_p_symbolic (self ):
2215
+ # Passing symbolic negative p does not raise an immediate error, but evaluating
2216
+ # logp raises a ParameterValueError
2217
+ with pytest .raises (ParameterValueError ):
2218
+ value = np .array ([[1 , 1 , 1 ]])
2219
+ invalid_dist = pm .Multinomial .dist (n = 1 , p = at .as_tensor_variable ([- 1 , 0.5 , 0.5 ]))
2200
2220
pm .logp (invalid_dist , value ).eval ()
2201
2221
2202
- value [1 ] -= 1
2203
- valid_dist = Multinomial .dist (n = 5 , p = np .ones (3 ) / 3 )
2204
- assert np .all (np .isfinite (pm .logp (valid_dist , value ).eval ()) == np .array ([True , False ]))
2222
+ def test_multinomial_p_not_normalized_symbolic (self ):
2223
+ # Passing symbolic p that do not add up to on does not raise any warning, but evaluating
2224
+ # logp raises a ParameterValueError
2225
+ with pytest .raises (ParameterValueError ):
2226
+ value = np .array ([[1 , 1 , 1 ]])
2227
+ invalid_dist = pm .Multinomial .dist (n = 1 , p = at .as_tensor_variable ([1 , 0.5 , 0.5 ]))
2228
+ pm .logp (invalid_dist , value ).eval ()
2205
2229
2206
2230
@pytest .mark .parametrize ("n" , [(10 ), ([10 , 11 ]), ([[5 , 6 ], [10 , 11 ]])])
2207
2231
@pytest .mark .parametrize (
@@ -2317,12 +2341,22 @@ def test_categorical_bounds(self):
2317
2341
np .array ([- 1 , - 1 , 0 , 0 ]),
2318
2342
],
2319
2343
)
2320
- def test_categorical_valid_p (self , p ):
2321
- with Model ():
2322
- x = Categorical ("x" , p = p )
2344
+ def test_categorical_negative_p (self , p ):
2345
+ with pytest .raises (ValueError , match = f"{ p } " ):
2346
+ with Model ():
2347
+ x = Categorical ("x" , p = p )
2323
2348
2324
- with pytest .raises (ParameterValueError ):
2325
- logp (x , 2 ).eval ()
2349
+ def test_categorical_negative_p_symbolic (self ):
2350
+ with pytest .raises (ParameterValueError ):
2351
+ value = np .array ([[1 , 1 , 1 ]])
2352
+ invalid_dist = pm .Categorical .dist (p = at .as_tensor_variable ([- 1 , 0.5 , 0.5 ]))
2353
+ pm .logp (invalid_dist , value ).eval ()
2354
+
2355
+ def test_categorical_p_not_normalized_symbolic (self ):
2356
+ with pytest .raises (ParameterValueError ):
2357
+ value = np .array ([[1 , 1 , 1 ]])
2358
+ invalid_dist = pm .Categorical .dist (p = at .as_tensor_variable ([2 , 2 , 2 ]))
2359
+ pm .logp (invalid_dist , value ).eval ()
2326
2360
2327
2361
@pytest .mark .parametrize ("n" , [2 , 3 , 4 ])
2328
2362
def test_categorical (self , n ):
@@ -2333,6 +2367,14 @@ def test_categorical(self, n):
2333
2367
lambda value , p : categorical_logpdf (value , p ),
2334
2368
)
2335
2369
2370
+ def test_categorical_p_not_normalized (self ):
2371
+ # test UserWarning is raised for p vals that sum to more than 1
2372
+ # and normaliation is triggered
2373
+ with pytest .warns (UserWarning , match = "[5]" ):
2374
+ with pm .Model () as m :
2375
+ x = pm .Categorical ("x" , p = [1 , 1 , 1 , 1 , 1 ])
2376
+ assert np .isclose (m .x .owner .inputs [3 ].sum ().eval (), 1.0 )
2377
+
2336
2378
@pytest .mark .parametrize ("n" , [2 , 3 , 4 ])
2337
2379
def test_orderedlogistic (self , n ):
2338
2380
self .check_logp (
0 commit comments