12
12
sampled_from , shared , builds )
13
13
14
14
from . import _array_module as xp , api_version
15
+ from . import array_helpers as ah
15
16
from . import dtype_helpers as dh
16
17
from . import shape_helpers as sh
17
18
from . import xps
@@ -211,6 +212,7 @@ def tuples(elements, *, min_size=0, max_size=None, unique_by=None, unique=False)
211
212
212
213
# Use this to avoid memory errors with NumPy.
213
214
# See https://github.com/numpy/numpy/issues/15753
215
+ # Note, the hypothesis default for max_dims is min_dims + 2 (i.e., 0 + 2)
214
216
def shapes (** kw ):
215
217
kw .setdefault ('min_dims' , 0 )
216
218
kw .setdefault ('min_side' , 0 )
@@ -280,25 +282,29 @@ def mutually_broadcastable_shapes(
280
282
281
283
# Note: This should become hermitian_matrices when complex dtypes are added
282
284
@composite
283
- def symmetric_matrices (draw , dtypes = xps .floating_dtypes (), finite = True ):
285
+ def symmetric_matrices (draw , dtypes = xps .floating_dtypes (), finite = True , bound = 10. ):
284
286
shape = draw (square_matrix_shapes )
285
287
dtype = draw (dtypes )
286
288
if not isinstance (finite , bool ):
287
289
finite = draw (finite )
288
290
elements = {'allow_nan' : False , 'allow_infinity' : False } if finite else None
289
291
a = draw (arrays (dtype = dtype , shape = shape , elements = elements ))
290
- upper = xp .triu (a )
291
- lower = xp .triu (a , k = 1 ).mT
292
- return upper + lower
292
+ at = ah ._matrix_transpose (a )
293
+ H = (a + at )* 0.5
294
+ if finite :
295
+ assume (not xp .any (xp .isinf (H )))
296
+ assume (xp .all ((H == 0. ) | ((1 / bound <= xp .abs (H )) & (xp .abs (H ) <= bound ))))
297
+ return H
293
298
294
299
@composite
295
300
def positive_definite_matrices (draw , dtypes = xps .floating_dtypes ()):
296
301
# For now just generate stacks of identity matrices
297
302
# TODO: Generate arbitrary positive definite matrices, for instance, by
298
303
# using something like
299
304
# https://github.com/scikit-learn/scikit-learn/blob/844b4be24/sklearn/datasets/_samples_generator.py#L1351.
300
- n = draw (integers (0 ))
301
- shape = draw (shapes ()) + (n , n )
305
+ base_shape = draw (shapes ())
306
+ n = draw (integers (0 , 8 )) # 8 is an arbitrary small but interesting-enough value
307
+ shape = base_shape + (n , n )
302
308
assume (prod (i for i in shape if i ) < MAX_ARRAY_SIZE )
303
309
dtype = draw (dtypes )
304
310
return broadcast_to (eye (n , dtype = dtype ), shape )
@@ -308,12 +314,18 @@ def invertible_matrices(draw, dtypes=xps.floating_dtypes(), stack_shapes=shapes(
308
314
# For now, just generate stacks of diagonal matrices.
309
315
n = draw (integers (0 , SQRT_MAX_ARRAY_SIZE ),)
310
316
stack_shape = draw (stack_shapes )
311
- d = draw (arrays (dtypes , shape = (* stack_shape , 1 , n ),
312
- elements = dict (allow_nan = False , allow_infinity = False )))
317
+ dtype = draw (dtypes )
318
+ elements = one_of (
319
+ from_dtype (dtype , min_value = 0.5 , allow_nan = False , allow_infinity = False ),
320
+ from_dtype (dtype , max_value = - 0.5 , allow_nan = False , allow_infinity = False ),
321
+ )
322
+ d = draw (arrays (dtype , shape = (* stack_shape , 1 , n ), elements = elements ))
323
+
313
324
# Functions that require invertible matrices may do anything when it is
314
325
# singular, including raising an exception, so we make sure the diagonals
315
326
# are sufficiently nonzero to avoid any numerical issues.
316
- assume (xp .all (xp .abs (d ) > 0.5 ))
327
+ assert xp .all (xp .abs (d ) >= 0.5 )
328
+
317
329
diag_mask = xp .arange (n ) == xp .reshape (xp .arange (n ), (n , 1 ))
318
330
return xp .where (diag_mask , d , xp .zeros_like (d ))
319
331
0 commit comments