[Numpy-discussion] Functions for indexing into certain parts of an array (2d)

Fernando Perez fperez.net at gmail.com
Sat Jun 6 14:45:09 EDT 2009

On Sat, Jun 6, 2009 at 11:35 AM, Gael
Varoquaux<gael.varoquaux at normalesup.org> wrote:
> I think they need examples. Right now, it is not clear at all to me what
> they do.

Cheers,

f

# With doctests, set to be repeatable by seeding the rng.

def structured_rand_arr(size, sample_func=np.random.random,
ltfac=None, utfac=None, fill_diag=None):
"""Make a structured random 2-d array of shape (size,size).

If no optional arguments are given, a symmetric array is returned.

Parameters
----------

size : int
Determines the shape of the output array: (size,size).

sample_func : function, optional.
Must be a function which when called with a 2-tuple of ints, returns a
2-d array of that shape.  By default, np.random.random is used, but any
other sampling function can be used as long as matches this API.

utfac : float, optional
Multiplicative factor for the lower triangular part of the matrix.

ltfac : float, optional
Multiplicative factor for the lower triangular part of the matrix.

fill_diag : float, optional
If given, use this value to fill in the diagonal.  Otherwise the diagonal
will contain random elements.

Examples
--------

>>> np.random.seed(0)
>>> structured_rand_arr(4)
array([[ 0.5488,  0.7152,  0.6028,  0.5449],
[ 0.7152,  0.6459,  0.4376,  0.8918],
[ 0.6028,  0.4376,  0.7917,  0.5289],
[ 0.5449,  0.8918,  0.5289,  0.0871]])
>>> structured_rand_arr(4,ltfac=-10,utfac=10,fill_diag=0.5)
array([[ 0.5   ,  8.3262,  7.7816,  8.7001],
[-8.3262,  0.5   ,  4.6148,  7.8053],
[-7.7816, -4.6148,  0.5   ,  9.4467],
[-8.7001, -7.8053, -9.4467,  0.5   ]])
"""
# Make a random array from the given sampling function
mat0 = sample_func((size,size))
# And the empty one we'll then fill in to return
mat = np.empty_like(mat0)
# Extract indices for upper-triangle, lower-triangle and diagonal
uidx = triu_indices(size,1)
lidx = tril_indices(size,-1)
didx = diag_indices(size)
# Extract each part from the original and copy it to the output, possibly
# applying multiplicative factors.  We check the factors instead of
# defaulting to 1.0 to avoid unnecessary floating point multiplications
# which could be noticeable for very large sizes.
if utfac:
mat[uidx] = utfac * mat0[uidx]
else:
mat[uidx] = mat0[uidx]
if ltfac:
mat[lidx] = ltfac * mat0.T[lidx]
else:
mat[lidx] = mat0.T[lidx]
# If fill_diag was provided, use it; otherwise take the values in the
# diagonal from the original random array.
if fill_diag is not None:
mat[didx] = fill_diag
else:
mat[didx] = mat0[didx]

return mat

def symm_rand_arr(size,sample_func=np.random.random,fill_diag=None):
"""Make a symmetric random 2-d array of shape (size,size).

Parameters
----------

n : int
Size of the output array.

fill_diag : float, optional
If given, use this value to fill in the diagonal.  Useful for

Examples
--------

>>> np.random.seed(0)
>>> symm_rand_arr(4)
array([[ 0.5488,  0.7152,  0.6028,  0.5449],
[ 0.7152,  0.6459,  0.4376,  0.8918],
[ 0.6028,  0.4376,  0.7917,  0.5289],
[ 0.5449,  0.8918,  0.5289,  0.0871]])
>>> symm_rand_arr(4,fill_diag=4)
array([[ 4.    ,  0.8326,  0.7782,  0.87  ],
[ 0.8326,  4.    ,  0.4615,  0.7805],
[ 0.7782,  0.4615,  4.    ,  0.9447],
[ 0.87  ,  0.7805,  0.9447,  4.    ]])
"""
return structured_rand_arr(size,sample_func,fill_diag=fill_diag)

def antisymm_rand_arr(size,sample_func=np.random.random):
"""Make an anti-symmetric random 2-d array of shape (size,size).

Parameters
----------

n : int
Size of the output array.

Examples
--------
>>> np.random.seed(0)
>>> antisymm_rand_arr(4)
array([[ 0.    ,  0.7152,  0.6028,  0.5449],
[-0.7152,  0.    ,  0.4376,  0.8918],
[-0.6028, -0.4376,  0.    ,  0.5289],
[-0.5449, -0.8918, -0.5289,  0.    ]])
"""
return structured_rand_arr(size,sample_func,ltfac=-1.0,fill_diag=0)