File: RandomArray2.py

package info (click to toggle)
python-numarray 1.5.2-4
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 8,668 kB
  • ctags: 11,384
  • sloc: ansic: 113,864; python: 22,422; makefile: 197; sh: 11
file content (333 lines) | stat: -rw-r--r-- 12,326 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
import ranlib2 as ranlib
import numarray.numeric as num
import numarray.linear_algebra as linalg
import sys
import math
import types as _types
import numarray.generic as _gen

__doc__ = """Random number array generators.

This module provides functions to generate numarray of random numbers.
"""

# Extended RandomArray to provide more distributions:
# normal, beta, chi square, F, multivariate normal,
# exponential, binomial, multinomial
# Lee Barford, Dec. 1999.

# Extended most functions to accept arrays or sequences as 
# arguments, with broadcasting when necessary.
# Peter J. Verveer, 2003.

ArgumentError = "ArgumentError"

def seed(x=0,y=0):
    """Set the RNG seed using the integers x, y; 
    If |y| == 0 set a random one from clock.
    """
    if type (x) != _types.IntType or type (y) != _types.IntType :
        raise ArgumentError, "seed requires integer arguments."
    if y == 0:
        import time
        t = time.time()*10**4
        ndigits = int(math.log10(t))
        base = 10**(ndigits/2)
        x = int(t/base)
        y = 1 + int(t%base)
    ranlib.set_seeds(x,y)

seed()

def get_seed():
    """Return the current seed pair"""
    return ranlib.get_seeds()

def _broadcast_arguments(args, shape):
    """If there are no arrays/sequences in the args tuple, return args
    and shape unchanged. Otherwise: if shape is empty, broadcast all
    arrays/sequences in the arguments to a common shape, and return
    the result together with the broadcasted shape. If shape is not
    empty, broadcast all arrays/sequences in the arguments to the
    given shape and return these together with the unchanged
    shape. Scalar arguments are never changed.
    """
    if isinstance(shape, _types.IntType): 
        shape = [shape]
    array_args = []
    for arg in args:
        if (isinstance(arg, num.ArrayType) or
            isinstance(arg, _types.ListType) or
            isinstance(arg, _types.TupleType)):
            array_args.append(num.array(arg))
    if len(array_args) > 0:
        if len(shape) == 0:
            array_args = _gen._nWayBroadcast(array_args)
            shape = array_args[0].shape
        else:
            for ii in range(len(array_args)):
                array_args[ii] = _gen._broadcast(num.array(array_args[ii]), shape) 
        new_args = []
        for arg in args:
            if (isinstance(arg, num.ArrayType) or
                isinstance(arg, _types.ListType) or
                isinstance(arg, _types.TupleType)):
                new_args.append(array_args.pop(0))
            else:
                new_args.append(arg)
            args = tuple(new_args)
    return args, shape

def _build_random_array(fun, args, shape=[]):
    """Build an array by applying function |fun| to the arguments in
    |args|, creating an array with the specified shape.
    Allows an integer shape n as a shorthand for (n,).
    """
    args, shape = _broadcast_arguments(args, shape)
    if len(shape) != 0:
        n = num.multiply.reduce(shape)
        s = apply(fun, args + (n,))
        s.setshape(shape)
        return s
    else:
        n = 1
        s = apply(fun, args + (n,))
        return s[0]

def random(shape=[]):
    """random(n) or random([n, m, ...])

    Returns array of random numbers in the range 0.0 to 1.0.
    """
    return _build_random_array(ranlib.sample, (), shape)

def uniform(minimum, maximum, shape=[]):
    """uniform([minimum,], maximum[, shape])

    Return array with shape |shape| of random Floats with all values
    > minimum and < maximum.    
    """
    (minimum, maximum), shape = _broadcast_arguments((minimum, maximum), shape)
    return minimum + (maximum-minimum)*random(shape)

def randint(minimum, maximum=None, shape=[]):
    """randint([minimum,] maximum[, shape])

    Return random integers >= mininimum, < maximum;
    if only one parameter specified, return random integers >= 0, < maximum.
    """
    if maximum is None:
        maximum, minimum = minimum, 0
    a = num.floor(uniform(minimum, maximum, shape))
    if isinstance(a, num.ArrayType):
        return a.astype(num.Int32)
    else:
        return int(a)
     
def random_integers(maximum, minimum=1, shape=[]):
    """Return array of random integers in interval [minimum, maximum]

    Note that this function has reversed arguments. It is simply a
    redirection through randint, and use of that function (randint) is
    suggested.
    """
    return randint(minimum, maximum+1, shape) 
     
def permutation(n):
    """A permutation of indices range(n)"""
    return num.argsort(random(n))

def standard_normal(shape=[]):
    """standard_normal(n) or standard_normal([n, m, ...])

    Returns array of random numbers normally distributed with mean 0
    and standard deviation 1.
    """
    return _build_random_array(ranlib.standard_normal, (), shape)

def normal(mean, std, shape=[]):
    """normal(mean, std, n) or normal(mean, std, [n, m, ...])

    Returns array of random numbers randomly distributed with
    specified mean and standard deviation
    """
    (mean, std), shape = _broadcast_arguments((mean, std), shape)
    s = standard_normal(shape)
    return s * std + mean

def multivariate_normal(mean, cov, shape=[]):
    """multivariate_normal(mean, cov) or multivariate_normal(mean, cov, [m, n, ...])

    Returns an array containing multivariate normally distributed
    random numbers with specified mean and covariance.

    |mean| must be a one-dimensional array. |cov| must be a square
    two-dimensional array with the same number of rows and columns as
    |mean| has elements.

    The first form returns a single 1-D array containing a
    multivariate normal.

    The second form returns an array of shape (m, n, ...,
    cov.getshape()[0]). In this case, output[i,j,...,:] is a 1-D array
    containing a multivariate normal.
    """
    # Check preconditions on arguments
    mean = num.array(mean)
    cov = num.array(cov)
    if len(mean.getshape()) != 1:
        raise ArgumentError, "mean must be 1 dimensional."
    if (len(cov.getshape()) != 2) or (cov.getshape()[0] != cov.getshape()[1]):
        raise ArgumentError, "cov must be 2 dimensional and square."
    if mean.getshape()[0] != cov.getshape()[0]:
        raise ArgumentError, "mean and cov must have same length."
    # Compute shape of output
    if isinstance(shape, _types.IntType): shape = [shape]
    final_shape = list(shape[:])
    final_shape.append(mean.getshape()[0])
    # Create a matrix of independent standard normally distributed random
    # numbers. The matrix has rows with the same length as mean and as
    # many rows are necessary to form a matrix of shape final_shape.
    x = ranlib.standard_normal(num.multiply.reduce(final_shape))
    x.setshape(num.multiply.reduce(final_shape[0:len(final_shape)-1]),
               mean.getshape()[0])
    # Transform matrix of standard normals into matrix where each row
    # contains multivariate normals with the desired covariance.
    # Compute A such that matrixmultiply(transpose(A),A) == cov.
    # Then the matrix products of the rows of x and A has the desired
    # covariance. Note that sqrt(s)*v where (u,s,v) is the singular value
    # decomposition of cov is such an A.
    (u,s,v) = linalg.singular_value_decomposition(cov)
    x = num.matrixmultiply(x*num.sqrt(s),v)
    # The rows of x now have the correct covariance but mean 0. Add
    # mean to each row. Then each row will have mean mean.
    num.add(mean,x,x)
    x.setshape(final_shape)
    return x

def exponential(mean, shape=[]):
    """exponential(mean, n) or exponential(mean, [n, m, ...])

    Returns array of random numbers exponentially distributed with
    specified mean
    """
    # If U is a random number uniformly distributed on [0,1], then
    #      -ln(U) is exponentially distributed with mean 1, and so
    #      -ln(U)*M is exponentially distributed with mean M.
    (mean,), shape = _broadcast_arguments((mean,), shape)
    x = random(shape)
    num.log(x, x)
    num.subtract(0.0, x, x)
    num.multiply(mean, x, x)
    return x

def beta(a, b, shape=[]):
    """beta(a, b) or beta(a, b, [n, m, ...]) returns array of beta distributed random numbers."""
    return _build_random_array(ranlib.beta, (a, b), shape)

def gamma(a, r, shape=[]):
    """gamma(a, r) or gamma(a, r, [n, m, ...]) returns array of gamma distributed random numbers."""
    return _build_random_array(ranlib.gamma, (a, r), shape)

def F(dfn, dfd, shape=[]):
    """F(dfn, dfd) or F(dfn, dfd, [n, m, ...])

    Returns array of F distributed random numbers with dfn degrees of
    freedom in the numerator and dfd degrees of freedom in the
    denominator.
    """
    (dfn, dfd), shape = _broadcast_arguments((dfn, dfd), shape)
    return ( chi_square(dfn, shape) / dfn) / ( chi_square(dfd, shape) / dfd)

def noncentral_F(dfn, dfd, nconc, shape=[]):
    """noncentral_F(dfn, dfd, nonc) or noncentral_F(dfn, dfd, nonc, [n, m, ...])

    Returns array of noncentral F distributed random numbers with dfn
    degrees of freedom in the numerator and dfd degrees of freedom in
    the denominator, and noncentrality parameter nconc.
    """
    (dfn, dfd, nconc), shape = _broadcast_arguments((dfn, dfd, nconc), shape)
    return ( noncentral_chi_square(dfn, nconc, shape) / dfn ) / ( chi_square(dfd, shape) /dfd )

def chi_square(df, shape=[]):
    """chi_square(df) or chi_square(df, [n, m, ...])

    Returns array of chi squared distributed random numbers with df
    degrees of freedom.
    """
    return _build_random_array(ranlib.chisquare, (df,), shape)

def noncentral_chi_square(df, nconc, shape=[]):
    """noncentral_chi_square(df, nconc) or chi_square(df, nconc, [n, m, ...])

    Returns array of noncentral chi squared distributed random numbers
    with df degrees of freedom and noncentrality parameter.
    """
    return _build_random_array(ranlib.noncentral_chisquare, (df, nconc), shape)

def binomial(trials, p, shape=[]):
    """binomial(trials, p) or binomial(trials, p, [n, m, ...])

    Returns array of binomially distributed random integers.

    |trials| is the number of trials in the binomial distribution.
    |p| is the probability of an event in each trial of the binomial
    distribution.
    """
    return _build_random_array(ranlib.binomial, (trials, p), shape)

def negative_binomial(trials, p, shape=[]):
    """negative_binomial(trials, p) or negative_binomial(trials, p, [n, m, ...])

    Returns array of negative binomially distributed random integers.

    |trials| is the number of trials in the negative binomial
    distribution. |p| is the probability of an event in each trial of
    the negative binomial distribution.
    """
    return _build_random_array(ranlib.negative_binomial, (trials, p), shape)

def multinomial(trials, probs, shape=[]):
    """multinomial(trials, probs) or multinomial(trials, probs, [n, m, ...])

    Returns array of multinomial distributed integer vectors.

    |trials| is the number of trials in each multinomial distribution. 
    |probs| is a one dimensional array. There are len(prob)+1 events. 
    prob[i] is the probability of the i-th event, 0<=i<len(prob). The
    probability of event len(prob) is 1.-num.sum(prob).

    The first form returns a single 1-D array containing one
    multinomially distributed vector.

    The second form returns an array of shape (m, n, ..., len(probs)). 
    In this case, output[i,j,...,:] is a 1-D array containing a
    multinomially distributed integer 1-D array.
    """
    # Check preconditions on arguments
    probs = num.array(probs)
    if len(probs.getshape()) != 1:
        raise ArgumentError, "probs must be 1 dimensional."
        # Compute shape of output
    if type(shape) == type(0): shape = [shape]
    final_shape = shape[:]
    final_shape.append(probs.getshape()[0]+1)
    x = ranlib.multinomial(trials, probs.astype(num.Float32),
                           num.multiply.reduce(shape))
    # Change its shape to the desire one
    x.setshape(final_shape)
    return x

def poisson(mean, shape=[]):
    """poisson(mean) or poisson(mean, [n, m, ...])

    Returns array of poisson distributed random integers with specifed
    mean.
    """
    return _build_random_array(ranlib.poisson, (mean,), shape)


from dtest import test
    
if __name__ == '__main__': 
    test()