~ubuntu-branches/ubuntu/karmic/python-scipy/karmic

« back to all changes in this revision

Viewing changes to Lib/stats/distributions.py

  • Committer: Bazaar Package Importer
  • Author(s): Daniel T. Chen (new)
  • Date: 2005-03-16 02:15:29 UTC
  • Revision ID: james.westby@ubuntu.com-20050316021529-xrjlowsejs0cijig
Tags: upstream-0.3.2
ImportĀ upstreamĀ versionĀ 0.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Functions to implement several important functions for 
 
2
#   various Continous and Discrete Probability Distributions
 
3
#
 
4
# Author:  Travis Oliphant  2002-2003
 
5
 
6
 
 
7
from __future__ import nested_scopes
 
8
import scipy
 
9
import scipy.special as special
 
10
import scipy.optimize as optimize
 
11
import Numeric as Num
 
12
import inspect
 
13
from Numeric import alltrue, where, arange, put, putmask, nonzero, \
 
14
     ravel, compress, take, ones, sum, shape, product, repeat, reshape, \
 
15
     zeros
 
16
from scipy_base.fastumath import *
 
17
from scipy_base import atleast_1d, polyval, angle, ceil, insert, extract, \
 
18
     any, argsort, argmax, argmin, vectorize, r_, asarray, nan, inf, select
 
19
import scipy_base
 
20
 
 
21
errp = special.errprint
 
22
arr = asarray
 
23
gam = special.gamma
 
24
 
 
25
import types, math
 
26
import stats as st
 
27
import rand
 
28
import rv
 
29
 
 
30
 
 
31
all = alltrue
 
32
sgf = vectorize
 
33
import new
 
34
 
 
35
def seed(x=0,y=0):
 
36
    """seed(x, y), set the seed using the integers x, y; 
 
37
    Set a random one from clock if  y == 0
 
38
    """
 
39
    if type (x) != types.IntType or type (y) != types.IntType :
 
40
        raise ArgumentError, "seed requires integer arguments."
 
41
    if y == 0:
 
42
        import random
 
43
        y = int(rv.initial_seed())
 
44
        x = random.randint(1,int(2l**31-2)) # Python 2.1 and 2.2 require this
 
45
                                            # bit of hackery to escape some 
 
46
                                            # wierd int/longint conversion
 
47
                                            # behavior
 
48
    rand.set_seeds(x,y)
 
49
 
 
50
seed()
 
51
 
 
52
def get_seed():
 
53
    "Return the current seed pair"
 
54
    return rand.get_seeds()
 
55
 
 
56
def _build_random_array(fun, args, size=None):
 
57
# Build an array by applying function fun to
 
58
# the arguments in args, creating an array with
 
59
# the specified shape.
 
60
# Allows an integer shape n as a shorthand for (n,).
 
61
    if isinstance(size, types.IntType): 
 
62
        size = [size]
 
63
    if size is not None and len(size) != 0:
 
64
        n = Num.multiply.reduce(size)
 
65
        s = apply(fun, args + (n,))
 
66
        s.shape = size
 
67
        return s
 
68
    else:
 
69
        n = 1
 
70
        s = apply(fun, args + (n,))
 
71
        return s[0]    
 
72
 
 
73
def random(size=None):
 
74
    "Returns array of random numbers between 0 and 1"
 
75
    return _build_random_array(rand.sample, (), size)
 
76
 
 
77
def random_integers(max, min=1, size=None):
 
78
    """random integers in range min to max inclusive"""
 
79
    return randint.rvs(min, max+1, size) 
 
80
     
 
81
def permutation(arg):
 
82
    """If arg is an integer, a permutation of indices arange(n), otherwise
 
83
    a permuation of the sequence"""
 
84
    if isinstance(arg,types.IntType):
 
85
        arg = Num.arange(arg)
 
86
    return rand.permutation(arg)
 
87
 
 
88
 
 
89
## Internal class to compute a ppf given a distribution.
 
90
##  (needs cdf function) and uses brentq from scipy.optimize
 
91
##  to compute ppf from cdf.
 
92
class general_cont_ppf:
 
93
    def __init__(self, dist, xa=-10.0, xb=10.0, xtol=1e-14):
 
94
        self.dist = dist
 
95
        self.cdf = eval('%scdf'%dist)
 
96
        self.xa = xa
 
97
        self.xb = xb
 
98
        self.xtol = xtol
 
99
        self.vecfunc = sgf(self._single_call,otypes='d')
 
100
    def _tosolve(self, x, q, *args):
 
101
        return apply(self.cdf, (x, )+args) - q
 
102
    def _single_call(self, q, *args):
 
103
        return scipy.optimize.brentq(self._tosolve, self.xa, self.xb, args=(q,)+args, xtol=self.xtol)
 
104
    def __call__(self, q, *args):
 
105
        return self.vecfunc(q, *args)
 
106
 
 
107
 
 
108
# Frozen RV class 
 
109
class rv_frozen:
 
110
    def __init__(self, dist, *args, **kwds):
 
111
        self.args = args
 
112
        self.kwds = kwds
 
113
        self.dist = dist
 
114
    def pdf(self,x):
 
115
        return self.dist.pdf(x,*self.args,**self.kwds)
 
116
    def cdf(self,x):
 
117
        return self.dist.cdf(x,*self.args,**self.kwds)
 
118
    def ppf(self,q):
 
119
        return self.dist.ppf(q,*self.args,**self.kwds)
 
120
    def isf(self,q):
 
121
        return self.dist.isf(q,*self.args,**self.kwds)
 
122
    def rvs(self, size=None):
 
123
        kwds = self.kwds
 
124
        kwds.update({'size':size})
 
125
        return self.dist.rvs(*self.args,**kwds)
 
126
    def sf(self,x):
 
127
        return self.dist.sf(x,*self.args,**self.kwds)
 
128
    def stats(self):
 
129
        return self.dist.stats(*self.args,**self.kwds)
 
130
 
 
131
    
 
132
            
 
133
##  NANs are returned for unsupported parameters.
 
134
##    location and scale parameters are optional for each distribution.
 
135
##    The shape parameters are generally required
 
136
##
 
137
##    The loc and scale parameters must be given as keyword parameters.
 
138
##    These are related to the common symbols in the .lyx file
 
139
 
 
140
##  skew is third central moment / variance**(1.5)
 
141
##  kurtosis is fourth central moment / variance**2 - 3
 
142
 
 
143
 
 
144
## References::
 
145
 
 
146
##  Documentation for ranlib, rv2, cdflib and
 
147
## 
 
148
##  Eric Wesstein's world of mathematics http://mathworld.wolfram.com/
 
149
##      http://mathworld.wolfram.com/topics/StatisticalDistributions.html
 
150
##
 
151
##  Documentation to Regress+ by Michael McLaughlin
 
152
##
 
153
##  Engineering and Statistics Handbook (NIST)
 
154
##      http://www.itl.nist.gov/div898/handbook/index.htm
 
155
##
 
156
##  Documentation for DATAPLOT from NIST
 
157
##      http://www.itl.nist.gov/div898/software/dataplot/distribu.htm
 
158
##
 
159
##  Norman Johnson, Samuel Kotz, and N. Balakrishnan "Continuous
 
160
##      Univariate Distributions", second edition,
 
161
##      Volumes I and II, Wiley & Sons, 1994.
 
162
 
 
163
 
 
164
## Each continuous random variable as the following methods
 
165
##
 
166
## rvs -- Random Variates (alternatively calling the class could produce these)
 
167
## pdf -- PDF
 
168
## cdf -- CDF
 
169
## sf  -- Survival Function (1-CDF)
 
170
## ppf -- Percent Point Function (Inverse of CDF)
 
171
## isf -- Inverse Survival Function (Inverse of SF)
 
172
## stats -- Return mean, variance, (Fisher's) skew, or (Fisher's) kurtosis
 
173
## nnlf  -- negative log likelihood function (to minimize)
 
174
## fit   -- Model-fitting
 
175
##
 
176
##  Maybe Later
 
177
##
 
178
##  hf  --- Hazard Function (PDF / SF)
 
179
##  chf  --- Cumulative hazard function (-log(SF))
 
180
##  psf --- Probability sparsity function (reciprocal of the pdf) in
 
181
##                units of percent-point-function (as a function of q).
 
182
##                Also, the derivative of the percent-point function.
 
183
 
 
184
## To define a new random variable you subclass the rv_continuous class
 
185
##   and re-define the 
 
186
##
 
187
##   _pdf method which will be given clean arguments (in between a and b)
 
188
##        and passing the argument check method
 
189
##
 
190
##      If postive argument checking is not correct for your RV
 
191
##      then you will also need to re-define
 
192
##   _argcheck
 
193
 
 
194
##   Correct, but potentially slow defaults exist for the remaining
 
195
##       methods but for speed and/or accuracy you can over-ride
 
196
##
 
197
##     _cdf, _ppf, _rvs, _isf, _sf
 
198
##
 
199
##   Rarely would you override _isf  and _sf but you could.
 
200
##
 
201
##   Statistics are computed using numerical integration by default.
 
202
##     For speed you can redefine this using
 
203
##
 
204
##    _stats  --- take shape parameters and return mu, mu2, g1, g2
 
205
##            --- If you can't compute one of these return it as None
 
206
##
 
207
##            --- Can also be defined with a keyword argument moments=<str>
 
208
##                  where <str> is a string composed of 'm', 'v', 's',
 
209
##                  and/or 'k'.  Only the components appearing in string
 
210
##                 should be computed and returned in the order 'm', 'v',
 
211
##                  's', or 'k'  with missing values returned as None
 
212
##
 
213
##    OR
 
214
##
 
215
##  You can override
 
216
##  
 
217
##    _munp    -- takes n and shape parameters and returns
 
218
##             --  then nth non-central moment of the distribution.
 
219
##       
 
220
 
 
221
def valarray(shape,value=nan,typecode=None):
 
222
    """Return an array of all value.
 
223
    """
 
224
    out = reshape(repeat([value],product(shape)),shape)
 
225
    if typecode is None:
 
226
        return out
 
227
    else:
 
228
        return out.astype(typecode)
 
229
 
 
230
def argsreduce(cond, *args):
 
231
    """Return a sequence of arguments converted to the dimensions of cond
 
232
    """
 
233
    newargs = list(args)
 
234
    expand_arr = (cond==cond)
 
235
    for k in range(len(args)):
 
236
        newargs[k] = extract(cond,arr(args[k])*expand_arr)
 
237
    return newargs    
 
238
 
 
239
class rv_continuous:
 
240
    """A Generic continuous random variable.
 
241
 
 
242
    Continuous random variables are defined from a standard form chosen
 
243
    for simplicity of representation.  The standard form may require
 
244
    some shape parameters to complete its specification.  The distributions
 
245
    also take optional location and scale parameters using loc= and scale=
 
246
    keywords (defaults: loc=0, scale=1)
 
247
 
 
248
    These shape, scale, and location parameters can be passed to any of the
 
249
    methods of the RV object such as the following:
 
250
 
 
251
    generic.rvs(<shape(s)>,loc=0,scale=1)
 
252
        - random variates 
 
253
 
 
254
    generic.pdf(x,<shape(s)>,loc=0,scale=1)
 
255
        - probability density function
 
256
 
 
257
    generic.cdf(x,<shape(s)>,loc=0,scale=1)
 
258
        - cumulative density function
 
259
 
 
260
    generic.sf(x,<shape(s)>,loc=0,scale=1)
 
261
        - survival function (1-cdf --- sometimes more accurate)
 
262
 
 
263
    generic.ppf(q,<shape(s)>,loc=0,scale=1)
 
264
        - percent point function (inverse of cdf --- percentiles)
 
265
 
 
266
    generic.isf(q,<shape(s)>,loc=0,scale=1)
 
267
        - inverse survival function (inverse of sf)
 
268
 
 
269
    generic.stats(<shape(s)>,loc=0,scale=1,moments='mv')
 
270
        - mean('m'), variance('v'), skew('s'), and/or kurtosis('k')
 
271
 
 
272
    generic.entropy(<shape(s)>,loc=0,scale=1)
 
273
        - (differential) entropy of the RV.
 
274
 
 
275
    Alternatively, the object may be called (as a function) to fix
 
276
       the shape, location, and scale parameters returning a
 
277
       "frozen" continuous RV object:
 
278
 
 
279
    myrv = generic(<shape(s)>,loc=0,scale=1)
 
280
        - frozen RV object with the same methods but holding the
 
281
            given shape, location, and scale fixed
 
282
    """
 
283
    def __init__(self, momtype=1, a=None, b=None, xa=-10.0, xb=10.0, xtol=1e-14, badvalue=None, name=None, longname=None, shapes=None, extradoc=None):
 
284
        if badvalue is None:
 
285
            badvalue = nan
 
286
        self.badvalue = badvalue
 
287
        self.name = name
 
288
        self.a = a
 
289
        self.b = b
 
290
        if a is None:
 
291
            self.a = -inf
 
292
        if b is None:
 
293
            self.b = inf
 
294
        self.xa = xa
 
295
        self.xb = xb
 
296
        self.xtol = xtol
 
297
        self._size = 1
 
298
        self.m = 0.0
 
299
        self.moment_type = momtype
 
300
        self.vecfunc = sgf(self._ppf_single_call,otypes='d')
 
301
        self.vecentropy = sgf(self._entropy,otypes='d')
 
302
        self.veccdf = sgf(self._cdf_single_call,otypes='d')
 
303
        self.expandarr = 1
 
304
        if momtype == 0:
 
305
            self.generic_moment = sgf(self._mom0_sc,otypes='d')
 
306
        else:
 
307
            self.generic_moment = sgf(self._mom1_sc,otypes='d')
 
308
        cdf_signature = inspect.getargspec(self._cdf.im_func)
 
309
        numargs1 = len(cdf_signature[0]) - 2
 
310
        pdf_signature = inspect.getargspec(self._pdf.im_func)
 
311
        numargs2 = len(pdf_signature[0]) - 2
 
312
        self.numargs = max(numargs1, numargs2)
 
313
 
 
314
        if longname is None:
 
315
            if name[0] in ['aeiouAEIOU']: hstr = "An "
 
316
            else: hstr = "A "
 
317
            longname = hstr + name
 
318
        if self.__doc__ is None:
 
319
            self.__doc__ = rv_continuous.__doc__
 
320
        if self.__doc__ is not None:
 
321
            self.__doc__ = self.__doc__.replace("A Generic",longname)
 
322
            if name is not None:
 
323
                self.__doc__ = self.__doc__.replace("generic",name)
 
324
            if shapes is None:
 
325
                self.__doc__ = self.__doc__.replace("<shape(s)>,","")
 
326
            else:
 
327
                self.__doc__ = self.__doc__.replace("<shape(s)>",shapes)
 
328
            if extradoc is not None:
 
329
                self.__doc__ = self.__doc__ + extradoc
 
330
 
 
331
    def _ppf_to_solve(self, x, q,*args):
 
332
        return apply(self.cdf, (x, )+args)-q
 
333
        
 
334
    def _ppf_single_call(self, q, *args):
 
335
        return scipy.optimize.brentq(self._ppf_to_solve, self.xa, self.xb, args=(q,)+args, xtol=self.xtol)
 
336
 
 
337
    # moment from definition
 
338
    def _mom_integ0(self, x,m,*args):
 
339
        return x**m * self.pdf(x,*args)
 
340
    def _mom0_sc(self, m,*args):
 
341
        return scipy.integrate.quad(self._mom_integ0, self.a,
 
342
                                    self.b, args=(m,)+args)[0]
 
343
    # moment calculated using ppf
 
344
    def _mom_integ1(self, q,m,*args):
 
345
        return (self.ppf(q,*args))**m
 
346
    def _mom1_sc(self, m,*args):
 
347
        return scipy.integrate.quad(self._mom_integ1, 0, 1,args=(m,)+args)[0]
 
348
 
 
349
    ## These are the methods you must define (standard form functions)
 
350
    def _argcheck(self, *args):
 
351
        # Default check for correct values on args and keywords.
 
352
        # Returns condition array of 1's where arguments are correct and
 
353
        #  0's where they are not.
 
354
        cond = 1
 
355
        for arg in args:
 
356
            cond = logical_and(cond,(arr(arg) > 0))
 
357
        return cond
 
358
 
 
359
    def _pdf(self,x,*args):
 
360
        return scipy.derivative(self._cdf,x,dx=1e-5,args=args,order=5)    
 
361
 
 
362
    ## Could also define any of these (return 1-d using self._size to get number)
 
363
    def _rvs(self, *args):
 
364
        ## Use basic inverse cdf algorithm for RV generation as default.
 
365
        U = rand.sample(self._size)
 
366
        Y = self._ppf(U,*args)
 
367
        return Y
 
368
 
 
369
    def _cdf_single_call(self, x, *args):
 
370
        return scipy.integrate.quad(self._pdf, self.a, x, args=args)[0]
 
371
 
 
372
    def _cdf(self, x, *args):
 
373
        return self.veccdf(x,*args)
 
374
 
 
375
    def _sf(self, x, *args):
 
376
        return 1.0-self._cdf(x,*args)
 
377
 
 
378
    def _ppf(self, q, *args):
 
379
        return self.vecfunc(q,*args)
 
380
 
 
381
    def _isf(self, q, *args):
 
382
        return self.vecfunc(1.0-q,*args)
 
383
 
 
384
    # The actual cacluation functions (no basic checking need be done)
 
385
    #  If these are defined, the others won't be looked at.
 
386
    #  Otherwise, the other set can be defined.
 
387
    def _stats(self,*args, **kwds):
 
388
        moments = kwds.get('moments')
 
389
        return None, None, None, None
 
390
 
 
391
    #  Central moments
 
392
    def _munp(self,n,*args):
 
393
        return self.generic_moment(n,*args)
 
394
 
 
395
    def __fix_loc_scale(self, args, loc, scale):
 
396
        N = len(args)
 
397
        if N > self.numargs:
 
398
            if N == self.numargs + 1 and loc is None:  # loc is given without keyword
 
399
                loc = args[-1]
 
400
            if N == self.numargs + 2 and scale is None: # loc and scale given without keyword
 
401
                loc, scale = args[-2:]
 
402
            args = args[:self.numargs]
 
403
        if scale is None:
 
404
            scale = 1.0
 
405
        if loc is None:
 
406
            loc = 0.0            
 
407
        return args, loc, scale
 
408
 
 
409
    # These are actually called, but should not
 
410
    #  be overwritten if you want to keep
 
411
    #  the error checking. 
 
412
    def rvs(self,*args,**kwds):
 
413
        """Random variates of given type.
 
414
 
 
415
        *args
 
416
        =====
 
417
        The shape parameter(s) for the distribution (see docstring of the
 
418
           instance object for more information)
 
419
        
 
420
        **kwds
 
421
        ======
 
422
        size  - number of random variates (default=1)
 
423
        loc   - location parameter (default=0)
 
424
        scale - scale parameter (default=1)
 
425
        """
 
426
        loc,scale,size=map(kwds.get,['loc','scale','size'])
 
427
        args, loc, scale = self.__fix_loc_scale(args, loc, scale)
 
428
        cond = logical_and(self._argcheck(*args),(scale >= 0))
 
429
        if not all(cond):
 
430
            raise ValueError, "Domain error in arguments."
 
431
 
 
432
        if size is None:
 
433
            size = 1
 
434
        else:
 
435
            self._size = product(size)
 
436
        if scipy.isscalar(size):
 
437
            self._size = size
 
438
            size = (size,)
 
439
 
 
440
        vals = reshape(self._rvs(*args),size)
 
441
        if scale == 0:
 
442
            return loc*ones(size,'d')
 
443
        else:
 
444
            return vals * scale + loc
 
445
        
 
446
    def pdf(self,x,*args,**kwds):
 
447
        """Probability density function at x of the given RV.
 
448
 
 
449
        *args
 
450
        =====
 
451
        The shape parameter(s) for the distribution (see docstring of the
 
452
           instance object for more information)
 
453
        
 
454
        **kwds
 
455
        ======
 
456
        loc   - location parameter (default=0)
 
457
        scale - scale parameter (default=1)
 
458
        """
 
459
        loc,scale=map(kwds.get,['loc','scale'])
 
460
        args, loc, scale = self.__fix_loc_scale(args, loc, scale)
 
461
        x,loc,scale = map(arr,(x,loc,scale))
 
462
        args = tuple(map(arr,args))
 
463
        x = arr((x-loc)*1.0/scale)
 
464
        cond0 = self._argcheck(*args) & (scale > 0)
 
465
        cond1 = (scale > 0) & (x > self.a) & (x < self.b)
 
466
        cond = cond0 & cond1
 
467
        output = zeros(shape(cond),'d')
 
468
        insert(output,(1-cond0)*(cond1==cond1),self.badvalue)
 
469
        goodargs = argsreduce(cond, *((x,)+args+(scale,)))
 
470
        scale, goodargs = goodargs[-1], goodargs[:-1]
 
471
        insert(output,cond,self._pdf(*goodargs) / scale)
 
472
        return output
 
473
 
 
474
    def cdf(self,x,*args,**kwds):
 
475
        """Cumulative distribution function at x of the given RV.
 
476
 
 
477
        *args
 
478
        =====
 
479
        The shape parameter(s) for the distribution (see docstring of the
 
480
           instance object for more information)
 
481
 
 
482
        **kwds
 
483
        ======
 
484
        loc   - location parameter (default=0)
 
485
        scale - scale parameter (default=1)
 
486
        """        
 
487
        loc,scale=map(kwds.get,['loc','scale'])
 
488
        args, loc, scale = self.__fix_loc_scale(args, loc, scale)
 
489
        x,loc,scale = map(arr,(x,loc,scale))
 
490
        args = tuple(map(arr,args))
 
491
        x = (x-loc)*1.0/scale
 
492
        cond0 = self._argcheck(*args) & (scale > 0)
 
493
        cond1 = (scale > 0) & (x > self.a) & (x < self.b)
 
494
        cond2 = (x >= self.b) & cond0
 
495
        cond = cond0 & cond1
 
496
        output = zeros(shape(cond),'d')
 
497
        insert(output,(1-cond0)*(cond1==cond1),self.badvalue)
 
498
        insert(output,cond2,1.0)
 
499
        goodargs = argsreduce(cond, *((x,)+args))
 
500
        insert(output,cond,self._cdf(*goodargs))
 
501
        return output
 
502
 
 
503
    def sf(self,x,*args,**kwds):
 
504
        """Survival function (1-cdf) at x of the given RV.
 
505
 
 
506
        *args
 
507
        =====
 
508
        The shape parameter(s) for the distribution (see docstring of the
 
509
           instance object for more information)
 
510
 
 
511
        **kwds
 
512
        ======
 
513
        loc   - location parameter (default=0)
 
514
        scale - scale parameter (default=1)
 
515
        """         
 
516
        loc,scale=map(kwds.get,['loc','scale'])
 
517
        args, loc, scale = self.__fix_loc_scale(args, loc, scale)
 
518
        x,loc,scale = map(arr,(x,loc,scale))
 
519
        args = tuple(map(arr,args))
 
520
        x = (x-loc)*1.0/scale
 
521
        cond0 = self._argcheck(*args) & (scale > 0)
 
522
        cond1 = (scale > 0) & (x > self.a) & (x < self.b)
 
523
        cond2 = cond0 & (x <= self.a)
 
524
        cond = cond0 & cond1
 
525
        output = zeros(shape(cond),'d')
 
526
        insert(output,(1-cond0)*(cond1==cond1),self.badvalue)
 
527
        insert(output,cond2,1.0)
 
528
        goodargs = argsreduce(cond, *((x,)+args))
 
529
        insert(output,cond,self._sf(*goodargs))
 
530
        return output
 
531
 
 
532
    def ppf(self,q,*args,**kwds):
 
533
        """Percent point function (inverse of cdf) at q of the given RV.
 
534
 
 
535
        *args
 
536
        =====
 
537
        The shape parameter(s) for the distribution (see docstring of the
 
538
           instance object for more information)
 
539
 
 
540
        **kwds
 
541
        ======
 
542
        loc   - location parameter (default=0)
 
543
        scale - scale parameter (default=1)
 
544
        """                 
 
545
        loc,scale=map(kwds.get,['loc','scale'])
 
546
        args, loc, scale = self.__fix_loc_scale(args, loc, scale)
 
547
        q,loc,scale = map(arr,(q,loc,scale))
 
548
        args = tuple(map(arr,args))
 
549
        cond0 = self._argcheck(*args) & (scale > 0) & (loc==loc)
 
550
        cond1 = (q > 0) & (q < 1)
 
551
        cond2 = (q==1) & cond0
 
552
        cond = cond0 & cond1
 
553
        output = valarray(shape(cond),value=self.a*scale + loc)
 
554
        insert(output,(1-cond0)+(1-cond1)*(q!=0.0), self.badvalue)
 
555
        insert(output,cond2,self.b*scale + loc)
 
556
        goodargs = argsreduce(cond, *((q,)+args+(scale,loc)))
 
557
        scale, loc, goodargs = goodargs[-2], goodargs[-1], goodargs[:-2]
 
558
        insert(output,cond,self._ppf(*goodargs)*scale + loc)
 
559
        return output
 
560
        
 
561
    def isf(self,q,*args,**kwds):
 
562
        """Inverse survival function at q of the given RV.
 
563
 
 
564
        *args
 
565
        =====
 
566
        The shape parameter(s) for the distribution (see docstring of the
 
567
           instance object for more information)
 
568
 
 
569
        **kwds
 
570
        ======
 
571
        loc   - location parameter (default=0)
 
572
        scale - scale parameter (default=1)
 
573
        """                         
 
574
        loc,scale=map(kwds.get,['loc','scale'])
 
575
        args, loc, scale = self.__fix_loc_scale(args, loc, scale)
 
576
        q,loc,scale = map(arr,(q,loc,scale))
 
577
        args = tuple(map(arr,args))
 
578
        cond0 = self._argcheck(*args) & (scale > 0) & (loc==loc)
 
579
        cond1 = (q > 0) & (q < 1)
 
580
        cond2 = (q==1) & cond0
 
581
        cond = cond0 & cond1
 
582
        output = valarray(shape(cond),value=self.b)
 
583
        insert(output,(1-cond0)*(cond1==cond1), self.badvalue)
 
584
        insert(output,cond2,self.a)
 
585
        goodargs = argsreduce(cond, *((1.0-q,)+args+(scale,loc)))
 
586
        scale, loc, goodargs = goodargs[-2], goodargs[-1], goodargs[:-2]
 
587
        insert(output,cond,self._ppf(*goodargs)*scale + loc)
 
588
        return output
 
589
 
 
590
    def stats(self,*args,**kwds):
 
591
        """Some statistics of the given RV
 
592
 
 
593
        *args
 
594
        =====
 
595
        The shape parameter(s) for the distribution (see docstring of the
 
596
           instance object for more information)
 
597
 
 
598
        **kwds
 
599
        ======
 
600
        loc     - location parameter (default=0)
 
601
        scale   - scale parameter (default=1)
 
602
        moments - a string composed of letters ['mvsk'] specifying
 
603
                   which moments to compute (default='mv')
 
604
                   'm' = mean,
 
605
                   'v' = variance,
 
606
                   's' = (Fisher's) skew,
 
607
                   'k' = (Fisher's) kurtosis.
 
608
        """                         
 
609
        loc,scale,moments=map(kwds.get,['loc','scale','moments'])
 
610
 
 
611
        N = len(args)
 
612
        if N > self.numargs:
 
613
            if N == self.numargs + 1 and loc is None:  # loc is given without keyword
 
614
                loc = args[-1]
 
615
            if N == self.numargs + 2 and scale is None: # loc and scale given without keyword
 
616
                loc, scale = args[-2:]
 
617
            if N == self.numargs + 3 and moments is None: # loc, scale, and moments
 
618
                loc, scale, moments = args[-3:]
 
619
            args = args[:self.numargs]
 
620
        if scale is None: scale = 1.0
 
621
        if loc is None: loc = 0.0
 
622
        if moments is None: moments = 'mv'
 
623
                        
 
624
        loc,scale = map(arr,(loc,scale))
 
625
        args = tuple(map(arr,args))
 
626
        cond = self._argcheck(*args) & (scale > 0) & (loc==loc)
 
627
 
 
628
        signature = inspect.getargspec(self._stats.im_func)
 
629
        if (signature[2] is not None) or ('moments' in signature[0]):
 
630
            mu, mu2, g1, g2 = self._stats(*args,**{'moments':moments})
 
631
        else:
 
632
            mu, mu2, g1, g2 = self._stats(*args)
 
633
        if g1 is None:
 
634
            mu3 = None
 
635
        else:
 
636
            mu3 = g1*(mu2**1.5)
 
637
        default = valarray(shape(cond), self.badvalue)
 
638
        output = []
 
639
 
 
640
        # Use only entries that are valid in calculation
 
641
        goodargs = argsreduce(cond, *(args+(scale,loc)))
 
642
        scale, loc, goodargs = goodargs[-2], goodargs[-1], goodargs[:-2]
 
643
 
 
644
        if 'm' in moments:
 
645
            if mu is None:
 
646
                mu = self._munp(1.0,*goodargs)
 
647
            out0 = default.copy()
 
648
            insert(out0,cond,mu*scale+loc)
 
649
            output.append(out0)
 
650
            
 
651
        if 'v' in moments:
 
652
            if mu2 is None:
 
653
                mu2p = self._munp(2.0,*goodargs)
 
654
                if mu is None:
 
655
                    mu = self._munp(1.0,*goodargs)
 
656
                mu2 = mu2p - mu*mu
 
657
            out0 = default.copy()
 
658
            insert(out0,cond,mu2*scale*scale)
 
659
            output.append(out0)
 
660
            
 
661
        if 's' in moments:
 
662
            if g1 is None:
 
663
                mu3p = self._munp(3.0,*goodargs)
 
664
                if mu is None:
 
665
                    mu = self._munp(1.0,*goodargs)                    
 
666
                if mu2 is None:
 
667
                    mu2p = self._munp(2.0,*goodargs)
 
668
                    mu2 = mu2p - mu*mu
 
669
                mu3 = mu3p - 3*mu*mu2 - mu**3
 
670
                g1 = mu3 / mu2**1.5
 
671
            out0 = default.copy()
 
672
            insert(out0,cond,g1)
 
673
            output.append(out0)
 
674
                
 
675
        if 'k' in moments:
 
676
            if g2 is None:
 
677
                mu4p = self._munp(4.0,*goodargs)
 
678
                if mu is None:
 
679
                    mu = self._munp(1.0,*goodargs)                    
 
680
                if mu2 is None:
 
681
                    mu2p = self._munp(2.0,*goodargs)
 
682
                    mu2 = mu2p - mu*mu
 
683
                if mu3 is None:
 
684
                    mu3p = self._munp(3.0,*goodargs)
 
685
                    mu3 = mu3p - 3*mu*mu2 - mu**3 
 
686
                mu4 = mu4p - 4*mu*mu3 - 6*mu*mu*mu2 - mu**4
 
687
                g2 = mu4 / mu2**2.0 - 3.0
 
688
            out0 = default.copy()
 
689
            insert(out0,cond,g2)
 
690
            output.append(out0)
 
691
 
 
692
        if len(output) == 1:
 
693
            return output[0]
 
694
        else:
 
695
            return tuple(output)
 
696
 
 
697
    def moment(self, n, *args):
 
698
        if (floor(n) != n):
 
699
            raise ValueError, "Moment must be an integer."
 
700
        if (n < 0): raise ValueError, "Moment must be positive."
 
701
        if (n == 0): return 1.0
 
702
        if (n > 0) and (n < 5):
 
703
            signature = inspect.getargspec(self._stats.im_func)
 
704
            if (signature[2] is not None) or ('moments' in signature[0]):
 
705
                dict = {'moments':{1:'m',2:'v',3:'vs',4:'vk'}[n]}
 
706
            else:
 
707
                dict = {}
 
708
            mu, mu2, g1, g2 = self._stats(*args,**dict)
 
709
            if (n==1):
 
710
                if mu is None: return self._munp(1,*args)
 
711
                else: return mu
 
712
            elif (n==2):
 
713
                if mu2 is None: return self._munp(2,*args)
 
714
                else: return mu
 
715
            elif (n==3):
 
716
                if g1 is None or mu2 is None: return self._munp(3,*args)
 
717
                else: return g1*(mu2**1.5)
 
718
            else: # (n==4)
 
719
                if g2 is None or mu2 is None: return self._munp(4,*args)
 
720
                else: return (g2+3.0)*(mu2**2.0)
 
721
        else:
 
722
            return self._munp(n,*args)
 
723
 
 
724
    def _nnlf(self, x, *args):
 
725
        return -sum(log(self._pdf(x, *args)))
 
726
 
 
727
    def nnlf(self, *args):
 
728
        # - sum (log pdf(x, theta))
 
729
        #   where theta are the parameters (including loc and scale)
 
730
        #
 
731
        try:
 
732
            x = args[-1]
 
733
            loc = args[-2]
 
734
            scale = args[-3]
 
735
            args = args[:-3]
 
736
        except IndexError:
 
737
            raise ValueError, "Not enough input arguments."
 
738
        if not self._argcheck(*args) or scale <= 0:
 
739
            return inf
 
740
        x = arr((x-loc) / scale)
 
741
        cond0 = (x <= self.a) | (x >= self.b)
 
742
        if (any(cond0)):
 
743
            return inf
 
744
        else:
 
745
            N = len(x)
 
746
            return self._nnlf(self, x, *args) + N*log(scale)
 
747
 
 
748
    def fit(self, data, *args, **kwds):
 
749
        loc0, scale0 = map(kwds.get, ['loc', 'scale'],[0.0, 1.0])
 
750
        Narg = len(args)
 
751
        if Narg != self.numargs:
 
752
            if Narg > self.numargs:
 
753
                raise ValueError, "Too many input arguments."
 
754
            else:
 
755
                args += (1.0,)*(self.numargs-Narg)
 
756
        # location and scale are at the end                
 
757
        x0 = args + (loc0, scale0)
 
758
        return optimize.fmin(self.nnlf,x0,args=(ravel(data),),disp=0)
 
759
 
 
760
    def est_loc_scale(self, data, *args):
 
761
        mu, mu2, g1, g2 = self.stats(*args,**{'moments':'mv'})
 
762
        muhat = stats.nanmean(data)
 
763
        mu2hat = stats.nanstd(data)
 
764
        Shat = sqrt(mu2hat / mu2)
 
765
        Lhat = muhat - Shat*mu
 
766
        return Lhat, Shat
 
767
 
 
768
    def freeze(self,*args,**kwds):
 
769
        return rv_frozen(self,*args,**kwds)
 
770
                
 
771
    def __call__(self, *args, **kwds):
 
772
        return self.freeze(*args, **kwds)
 
773
 
 
774
    def _entropy(self, *args):
 
775
        def integ(x):
 
776
            val = self._pdf(x, *args)
 
777
            return val*log(val)
 
778
        return -scipy.integrate.quad(integ,self.a,self.b)[0]
 
779
 
 
780
    def entropy(self, *args, **kwds):
 
781
        loc,scale=map(kwds.get,['loc','scale'])
 
782
        args, loc, scale = self.__fix_loc_scale(args, loc, scale)
 
783
        args = map(arr,args)
 
784
        cond0 = self._argcheck(*args) & (scale > 0) & (loc==loc)
 
785
        output = zeros(shape(cond0),'d')
 
786
        insert(output,(1-cond0),self.badvalue)
 
787
        goodargs = argsreduce(cond0, *args)
 
788
        insert(output,cond0,self.vecentropy(*goodargs)+log(scale))
 
789
        return output                
 
790
 
 
791
_EULER = 0.577215664901532860606512090082402431042  # -special.psi(1)
 
792
_ZETA3 = 1.202056903159594285399738161511449990765  # special.zeta(3,1)  Apery's constant
 
793
 
 
794
## Kolmogorov-Smirnov one-sided and two-sided test statistics
 
795
 
 
796
class ksone_gen(rv_continuous):
 
797
    def _cdf(self,x,n):
 
798
        return 1.0-special.smirnov(n,x)
 
799
    def _ppf(self,q,n):
 
800
        return special.smirnovi(n,1.0-q)
 
801
ksone = ksone_gen(a=0.0,name='ksone', longname="Kolmogorov-Smirnov "\
 
802
                  "A one-sided test statistic.", shapes="n",
 
803
                  extradoc="""
 
804
 
 
805
General Kolmogorov-Smirnov one-sided test.
 
806
"""
 
807
                  )
 
808
 
 
809
class kstwobign_gen(rv_continuous):
 
810
    def _cdf(self,x):
 
811
        return 1.0-special.kolmogorov(x)
 
812
    def _ppf(self,q):
 
813
        return special.kolmogi(1.0-q)
 
814
kstwobign = kstwobign_gen(a=0.0,name='kstwobign', longname='Kolmogorov-Smirnov two-sided (for large N)', extradoc="""
 
815
 
 
816
Kolmogorov-Smirnov two-sided test for large N
 
817
"""
 
818
                          )
 
819
 
 
820
 
 
821
## Normal distribution
 
822
 
 
823
# loc = mu, scale = std
 
824
class norm_gen(rv_continuous):
 
825
    def _rvs(self):
 
826
        return rand.standard_normal(self._size)
 
827
    def _pdf(self,x):
 
828
        return 1.0/sqrt(2*pi)*exp(-x**2/2.0)
 
829
    def _cdf(self,x):
 
830
        return special.ndtr(x)
 
831
    def _ppf(self,q):
 
832
        return special.ndtri(q)
 
833
    def _stats(self):
 
834
        return 0.0, 1.0, 0.0, 0.0
 
835
    def _entropy(self):
 
836
        return 0.5*(log(2*pi)+1)
 
837
norm = norm_gen(name='norm',longname='A normal',extradoc="""
 
838
 
 
839
Normal distribution
 
840
 
 
841
The location (loc) keyword specifies the mean.
 
842
The scale (scale) keyword specifies the standard deviation.
 
843
""")
 
844
 
 
845
## Alpha distribution
 
846
##
 
847
class alpha_gen(rv_continuous):
 
848
    def _pdf(self, x, a):
 
849
        return 1.0/arr(x**2)/special.ndtr(a)*norm.pdf(a-1.0/x)
 
850
    def _cdf(self, x, a):
 
851
        return special.ndtr(a-1.0/x) / special.ndtr(a)
 
852
    def _ppf(self, q, a):
 
853
        return 1.0/arr(a-special.ndtri(q*special.ndtr(a)))
 
854
    def _stats(self):
 
855
        return [inf]*2 + [nan]*2
 
856
alpha = alpha_gen(a=0.0,name='alpha',shapes='a',extradoc="""
 
857
 
 
858
Alpha distribution
 
859
""")
 
860
 
 
861
## Anglit distribution
 
862
##
 
863
class anglit_gen(rv_continuous):
 
864
    def _pdf(self, x):
 
865
        return cos(2*x)
 
866
    def _cdf(self, x):
 
867
        return sin(x+pi/4)**2.0
 
868
    def _ppf(self, q):
 
869
        return (arcsin(sqrt(q))-pi/4)
 
870
    def _stats(self):
 
871
        return 0.0, pi*pi/16-0.5, 0.0, -2*(pi**4 - 96)/(pi*pi-8)**2
 
872
    def _entropy(self):
 
873
        return 1-log(2)
 
874
anglit = anglit_gen(a=-pi/4,b=pi/4,name='anglit', extradoc="""
 
875
 
 
876
Anglit distribution
 
877
 
 
878
""")
 
879
 
 
880
 
 
881
## Arcsine distribution
 
882
##
 
883
class arcsine_gen(rv_continuous):
 
884
    def _pdf(self, x):
 
885
        return 1.0/pi/sqrt(x*(1-x))
 
886
    def _cdf(self, x):
 
887
        return 2.0/pi*arcsin(sqrt(x))
 
888
    def _ppf(self, q):
 
889
        return sin(pi/2.0*q)**2.0
 
890
    def _stats(self):
 
891
        mup = 0.5, 3.0/8.0, 15.0/48.0, 35.0/128.0
 
892
        mu = 0.5
 
893
        mu2 = 1.0/8
 
894
        g1 = 0
 
895
        g2 = -3.0/2.0
 
896
        return mu, mu2, g1, g2
 
897
    def _entropy(self):
 
898
        return -0.24156447527049044468
 
899
arcsine = arcsine_gen(a=0.0,b=1.0,name='arcsine',extradoc="""
 
900
 
 
901
Arcsine distribution
 
902
""")
 
903
 
 
904
 
 
905
## Beta distribution
 
906
##
 
907
class beta_gen(rv_continuous):
 
908
    def _rvs(self, a, b):
 
909
        return rand.beta(a,b,self._size)
 
910
    def _pdf(self, x, a, b):
 
911
        Px = (1.0-x)**(b-1.0) * x**(a-1.0)
 
912
        Px /= special.beta(a,b)
 
913
        return Px
 
914
    def _cdf(self, x, a, b):
 
915
        return special.btdtr(a,b,x)
 
916
    def _ppf(self, q, a, b):
 
917
        return special.btdtri(a,b,q)
 
918
    def _stats(self, a, b):
 
919
        mn = a *1.0 / (a + b)
 
920
        var = (a*b*1.0)*(a+b+1.0)/(a+b)**2.0
 
921
        g1 = 2.0*(b-a)*sqrt((1.0+a+b)/(a*b)) / (2+a+b)
 
922
        g2 = 6.0*(a**3 + a**2*(1-2*b) + b**2*(1+b) - 2*a*b*(2+b))
 
923
        g2 /= a*b*(a+b+2)*(a+b+3)
 
924
        return mn, var, g1, g2  
 
925
beta = beta_gen(a=0.0, b=1.0, name='beta',shapes='a,b',extradoc="""
 
926
 
 
927
Beta distribution
 
928
""")
 
929
 
 
930
## Beta Prime
 
931
class betaprime_gen(rv_continuous):
 
932
    def _rvs(self, a, b):
 
933
        u1 = gamma.rvs(a,size=self._size)
 
934
        u2 = gamma.rvs(b,size=self._size)
 
935
        return (u1 / u2)
 
936
    def _pdf(self, x, a, b):
 
937
        return 1.0/special.beta(a,b)*x**(a-1.0)/(1+x)**(a+b)
 
938
    def _cdf(self, x, a, b):
 
939
        x = where(x==1.0, 1.0-1e-6,x)
 
940
        return pow(x,a)*special.hyp2f1(a+b,a,1+a,-x)/a/special.beta(a,b)
 
941
    def _munp(self, n, a, b):
 
942
        if (n == 1.0):
 
943
            return where(b > 1, a/(b-1.0), inf)
 
944
        elif (n == 2.0):
 
945
            return where(b > 2, a*(a+1.0)/((b-2.0)*(b-1.0)), inf)
 
946
        elif (n == 3.0):
 
947
            return where(b > 3, a*(a+1.0)*(a+2.0)/((b-3.0)*(b-2.0)*(b-1.0)),
 
948
                         inf)
 
949
        elif (n == 4.0):
 
950
            return where(b > 4,
 
951
                         a*(a+1.0)*(a+2.0)*(a+3.0)/((b-4.0)*(b-3.0) \
 
952
                                                    *(b-2.0)*(b-1.0)), inf)
 
953
        else:
 
954
            raise NotImplementedError
 
955
betaprime = betaprime_gen(a=0.0, b=500.0, name='betaprime', shapes='a,b',
 
956
                          extradoc="""
 
957
 
 
958
Beta prime distribution
 
959
""")
 
960
 
 
961
## Bradford
 
962
##
 
963
 
 
964
class bradford_gen(rv_continuous):
 
965
    def _pdf(self, x, c):
 
966
        return  c / (c*x + 1.0) / log(1.0+c)
 
967
    def _cdf(self, x, c):
 
968
        return log(1.0+c*x) / log(c+1.0)
 
969
    def _ppf(self, q, c):
 
970
        return ((1.0+c)**q-1)/c
 
971
    def _stats(self, c, moments='mv'):
 
972
        k = log(1.0+c)
 
973
        mu = (c-k)/(c*k)
 
974
        mu2 = ((c+2.0)*k-2.0*c)/(2*c*k*k)
 
975
        g1 = None
 
976
        g2 = None
 
977
        if 's' in moments:
 
978
            g1 = sqrt(2)*(12*c*c-9*c*k*(c+2)+2*k*k*(c*(c+3)+3))
 
979
            g1 /= sqrt(c*(c*(k-2)+2*k))*(3*c*(k-2)+6*k)
 
980
        if 'k' in moments:
 
981
            g2 = c**3*(k-3)*(k*(3*k-16)+24)+12*k*c*c*(k-4)*(k-3) \
 
982
                 + 6*c*k*k*(3*k-14) + 12*k**3
 
983
            g2 /= 3*c*(c*(k-2)+2*k)**2
 
984
        return mu, mu2, g1, g2
 
985
    def _entropy(self, c):
 
986
        k = log(1+c)
 
987
        return k/2.0 - log(c/k)
 
988
bradford = bradford_gen(a=0.0, b=1.0, name='bradford', longname="A Bradford",
 
989
                        shapes='c', extradoc="""
 
990
 
 
991
Bradford distribution
 
992
""")
 
993
 
 
994
 
 
995
## Burr
 
996
 
 
997
# burr with d=1 is called the fisk distribution
 
998
class burr_gen(rv_continuous):
 
999
    def _pdf(self, x, c, d):
 
1000
        return c*d*(x**(-c-1.0))*((1+x**(-c*1.0))**(-d-1.0))
 
1001
    def _cdf(self, x, c, d):
 
1002
        return (1+x**(-c*1.0))**(-d**1.0)
 
1003
    def _ppf(self, q, c, d):
 
1004
        return (q**(-1.0/d)-1)**(-1.0/c)
 
1005
    def _stats(self, c, d, moments='mv'):
 
1006
        g2c, g2cd = gam(1-2.0/c), gam(2.0/c+d)
 
1007
        g1c, g1cd = gam(1-1.0/c), gam(1.0/c+d)
 
1008
        gd = gam(d)
 
1009
        k = gd*g2c*g2cd - g1c**2 * g1cd**2
 
1010
        mu = g1c*g1cd / gd
 
1011
        mu2 = k / gd**2.0
 
1012
        g1, g2 = None, None
 
1013
        g3c, g3cd = None, None
 
1014
        if 's' in moments:
 
1015
            g3c, g3cd = gam(1-3.0/c), gam(3.0/c+d)
 
1016
            g1 = 2*g1c**3 * g1cd**3 + gd*gd*g3c*g3cd - 3*gd*g2c*g1c*g1cd*g2cd
 
1017
            g1 /= sqrt(k**3)
 
1018
        if 'k' in moments:
 
1019
            if g3c is None:
 
1020
                g3c = gam(1-3.0/c)
 
1021
            if g3cd is None:
 
1022
                g3cd = gam(3.0/c+d)
 
1023
            g4c, g4cd = gam(1-4.0/c), gam(4.0/c+d)
 
1024
            g2 = 6*gd*g2c*g2cd * g1c**2 * g1cd**2 + gd**3 * g4c*g4cd
 
1025
            g2 -= 3*g1c**4 * g1cd**4 -4*gd**2*g3c*g1c*g1cd*g3cd
 
1026
        return mu, mu2, g1, g2
 
1027
burr = burr_gen(a=0.0, name='burr', longname="Burr",
 
1028
                shapes="c,d", extradoc="""
 
1029
 
 
1030
Burr distribution
 
1031
""")
 
1032
    
 
1033
# Fisk distribution
 
1034
# burr is a generalization
 
1035
 
 
1036
class fisk_gen(burr_gen):
 
1037
    def _pdf(self, x, c):
 
1038
        return burr_gen._pdf(self, x, c, 1.0)
 
1039
    def _cdf(self, x, c):
 
1040
        return burr_gen._cdf(self, x, c, 1.0)
 
1041
    def _ppf(self, x, c):
 
1042
        return burr_gen._ppf(self, x, c, 1.0)
 
1043
    def _stats(self, c):
 
1044
        return burr_gen._stats(self, c, 1.0)
 
1045
    def _entropy(self, c):
 
1046
        return 2 - log(c)
 
1047
fisk = fisk_gen(a=0.0, name='fink', longname="A funk",
 
1048
                shapes='c', extradoc="""
 
1049
 
 
1050
Fink distribution.
 
1051
"""
 
1052
                )
 
1053
 
 
1054
## Cauchy
 
1055
 
 
1056
# median = loc
 
1057
 
 
1058
class cauchy_gen(rv_continuous):
 
1059
    def _pdf(self, x):
 
1060
        return 1.0/pi/(1.0+x*x)
 
1061
    def _cdf(self, x):
 
1062
        return 0.5 + 1.0/pi*arctan(x)
 
1063
    def _ppf(self, q):
 
1064
        return tan(pi*q-pi/2.0)
 
1065
    def _sf(self, x):
 
1066
        return 0.5 - 1.0/pi*arctan(x)
 
1067
    def _isf(self, q):
 
1068
        return tan(pi/2.0-pi*q)
 
1069
    def _stats(self):
 
1070
        return inf, inf, nan, nan
 
1071
    def _entropy(self):
 
1072
        return log(4*pi)
 
1073
cauchy = cauchy_gen(name='cauchy',longname='Cauchy',extradoc="""
 
1074
 
 
1075
Cauchy distribution
 
1076
"""
 
1077
                    )
 
1078
 
 
1079
## Chi
 
1080
##   (positive square-root of chi-square)
 
1081
##   chi(1, loc, scale) = halfnormal
 
1082
##   chi(2, 0, scale) = Rayleigh
 
1083
##   chi(3, 0, scale) = MaxWell
 
1084
 
 
1085
class chi_gen(rv_continuous):
 
1086
    def _rvs(self, df):
 
1087
        return sqrt(chi2.rvs(df,size=self._size))
 
1088
    def _pdf(self, x, df):
 
1089
        return x**(df-1.)*exp(-x*x*0.5)/(2.0)**(df*0.5-1)/gam(df*0.5)
 
1090
    def _cdf(self, x, df):
 
1091
        return special.gammainc(df*0.5,0.5*x*x)
 
1092
    def _ppf(self, q, df):
 
1093
        return sqrt(2*special.gammaincinv(df*0.5,q))
 
1094
    def _stats(self, df):
 
1095
        mu = sqrt(2)*special.gamma(df/2.0+0.5)/special.gamma(df/2.0)
 
1096
        mu2 = df - mu*mu
 
1097
        g1 = (2*mu**3.0 + mu*(1-2*df))/arr(mu2**1.5)
 
1098
        g2 = 2*df*(1.0-df)-6*mu**4 + 4*mu**2 * (2*df-1)
 
1099
        g2 /= arr(mu2**2.0)
 
1100
        return mu, mu2, g1, g2
 
1101
chi = chi_gen(a=0.0,name='chi',shapes='df',extradoc="""
 
1102
 
 
1103
Chi distribution
 
1104
"""
 
1105
              )
 
1106
    
 
1107
 
 
1108
## Chi-squared (gamma-distributed with loc=0 and scale=2 and shape=df/2)
 
1109
class chi2_gen(rv_continuous):
 
1110
    def _rvs(self, df):
 
1111
        return rand.chi2(df,self._size)
 
1112
    def _pdf(self, x, df):
 
1113
        Px = x**(df/2.0-1)*exp(-x/2.0)
 
1114
        Px /= special.gamma(df/2.0)* 2**(df/2.0)
 
1115
        return Px
 
1116
    def _cdf(self, x, df):
 
1117
        return special.chdtr(df, x)
 
1118
    def _sf(self, x, df):
 
1119
        return special.chdtrc(df, x)
 
1120
    def _isf(self, p, df):
 
1121
        return special.chdtri(df, p)
 
1122
    def _ppf(self, p, df):
 
1123
        return self._isf(1.0-p, df)
 
1124
    def _stats(self, df):
 
1125
        mu = df
 
1126
        mu2 = 2*df
 
1127
        g1 = 2*sqrt(2.0/df)
 
1128
        g2 = 12.0/df
 
1129
        return mu, mu2, g1, g2
 
1130
chi2 = chi2_gen(a=0.0,name='chi2',longname='A chi-squared',shapes='df',
 
1131
                extradoc="""
 
1132
 
 
1133
Chi-squared distribution
 
1134
"""
 
1135
                )
 
1136
 
 
1137
## Cosine (Approximation to the Normal)
 
1138
class cosine_gen(rv_continuous):
 
1139
    def _pdf(self, x):
 
1140
        return 1.0/2/pi*(1+cos(x))
 
1141
    def _cdf(self, x):
 
1142
        return 1.0/2/pi*(pi + x + sin(x))
 
1143
    def _stats(self):
 
1144
        return 0.0, pi*pi/3.0-2.0, 0.0, -6.0*(pi**4-90)/(5.0*(pi*pi-6)**2)
 
1145
    def _entropy(self):
 
1146
        return log(4*pi)-1.0
 
1147
cosine = cosine_gen(a=-pi,b=pi,name='cosine',extradoc="""
 
1148
 
 
1149
Cosine distribution (Approximation to the normal)
 
1150
""")
 
1151
 
 
1152
## Double Gamma distribution
 
1153
class dgamma_gen(rv_continuous):
 
1154
    def _rvs(self, a):
 
1155
        u = random(size=self._size)
 
1156
        return (gamma.rvs(a,size=self._size)*Num.where(u>=0.5,1,-1))
 
1157
    def _pdf(self, x, a):
 
1158
        ax = abs(x)
 
1159
        return 1.0/(2*special.gamma(a))*ax**(a-1.0) * exp(-ax)
 
1160
    def _cdf(self, x, a):
 
1161
        fac = 0.5*special.gammainc(a,abs(x))
 
1162
        return where(x>0,0.5+fac,0.5-fac)
 
1163
    def _sf(self, x, a):
 
1164
        fac = 0.5*special.gammainc(a,abs(x))
 
1165
        return where(x>0,0.5-0.5*fac,0.5+0.5*fac)        
 
1166
    def _ppf(self, q, a):
 
1167
        fac = special.gammainccinv(a,1-abs(2*q-1))
 
1168
        return where(q>0.5, fac, -fac)
 
1169
    def _stats(self, a):
 
1170
        mu2 = a*(a+1.0)
 
1171
        return 0.0, mu2, 0.0, (a+2.0)*(a+3.0)/mu2-3.0
 
1172
dgamma = dgamma_gen(name='dgamma',longname="A double gamma",
 
1173
                    shapes='a',extradoc="""
 
1174
 
 
1175
Double gamma distribution
 
1176
"""
 
1177
                    )
 
1178
 
 
1179
## Double Weibull distribution
 
1180
##
 
1181
class dweibull_gen(rv_continuous):
 
1182
    def _rvs(self, c):
 
1183
        u = random(size=self._size)
 
1184
        return weibull_min.rvs(c, size=self._size)*(Num.where(u>=0.5,1,-1))    
 
1185
    def _pdf(self, x, c):
 
1186
        ax = abs(x)
 
1187
        Px = c/2.0*ax**(c-1.0)*exp(-ax**c)
 
1188
        return Px
 
1189
    def _cdf(self, x, c):
 
1190
        Cx1 = 0.5*exp(-abs(x)**c)
 
1191
        return where(x > 0, 1-Cx1, Cx1)
 
1192
    def _ppf(self, q, c):
 
1193
        fac = where(q<=0.5,2*q,2*q-1)
 
1194
        fac = pow(arr(log(1.0/fac)),1.0/c)
 
1195
        return where(q>0.5,fac,-fac)
 
1196
    def _stats(self, c):
 
1197
        var = gam(1+2.0/c)
 
1198
        return 0.0, var, 0.0, gam(1+4.0/c)/var
 
1199
dweibull = dweibull_gen(name='dweibull',longname="A double Weibull",
 
1200
                        shapes='c',extradoc="""
 
1201
 
 
1202
Double Weibull distribution
 
1203
"""
 
1204
                        )
 
1205
 
 
1206
## ERLANG
 
1207
##
 
1208
## Special case of the Gamma distribution with shape parameter an integer.
 
1209
##
 
1210
class erlang_gen(rv_continuous):
 
1211
    def _rvs(self, n):
 
1212
        return gamma.rvs(n,size=self._size)
 
1213
    def _arg_check(self, n):
 
1214
        return (n > 0) & (floor(n)==n)
 
1215
    def _pdf(self, x, n):
 
1216
        Px = (x)**(n-1.0)*exp(-x)/special.gamma(n)
 
1217
        return Px
 
1218
    def _cdf(self, x, n):
 
1219
        return special.gdtr(1.0,n,x)
 
1220
    def _sf(self, x, n):
 
1221
        return special.gdtrc(1.0,n,x)
 
1222
    def _ppf(self, q, n):
 
1223
        return special.gdtrix(1.0, n, q)
 
1224
    def _stats(self, n):
 
1225
        n = n*1.0
 
1226
        return n, n, 2/sqrt(n), 6/n
 
1227
    def _entropy(self, n):
 
1228
        return special.psi(n)*(1-n) + 1 + special.gammaln(n)        
 
1229
erlang = erlang_gen(a=0.0,name='erlang',longname='An Erlang',
 
1230
                    shapes='n',extradoc="""
 
1231
 
 
1232
Erlang distribution (Gamma with integer shape parameter)
 
1233
"""
 
1234
                    )
 
1235
       
 
1236
## Exponential (gamma distributed with a=1.0, loc=loc and scale=scale)
 
1237
## scale == 1.0 / lambda
 
1238
 
 
1239
class expon_gen(rv_continuous):
 
1240
    def _rvs(self):
 
1241
        return rand.standard_exp(self._size)
 
1242
    def _pdf(self, x):
 
1243
        return exp(-x)
 
1244
    def _cdf(self, x):
 
1245
        return 1.0-exp(-x)
 
1246
    def _ppf(self, q):
 
1247
        return -log(1.0-q)
 
1248
    def _stats(self):
 
1249
        return 1.0, 1.0, 2.0, 6.0
 
1250
    def _entropy(self):
 
1251
        return 1.0
 
1252
expon = expon_gen(a=0.0,name='expon',longname="An exponential",
 
1253
                  extradoc="""
 
1254
 
 
1255
Exponential distribution
 
1256
"""
 
1257
                  )
 
1258
 
 
1259
 
 
1260
## Exponentiated Weibull
 
1261
class exponweib_gen(rv_continuous):
 
1262
    def _pdf(self, x, a, c):
 
1263
        exc = exp(-x**c)
 
1264
        return a*c*(1-exc)**arr(a-1) * exc * x**arr(c-1)
 
1265
    def _cdf(self, x, a, c):
 
1266
        exc = exp(-x**c)
 
1267
        return arr((1-exc)**a)
 
1268
    def _ppf(self, q, a, c):
 
1269
        return (-log(1-q**(1.0/a)))**arr(1.0/c)
 
1270
exponweib = exponweib_gen(a=0.0,name='exponweib',
 
1271
                          longname="An exponentiated Weibull",
 
1272
                          shapes="a,c",extradoc="""
 
1273
 
 
1274
Exponentiated Weibull distribution                          
 
1275
"""
 
1276
                          )
 
1277
                   
 
1278
## Exponential Power
 
1279
 
 
1280
class exponpow_gen(rv_continuous):
 
1281
    def _pdf(self, x, b):
 
1282
        xbm1 = arr(x**(b-1.0))
 
1283
        xb = xbm1 * x
 
1284
        return exp(1)*b*xbm1 * exp(xb - exp(xb))
 
1285
    def _cdf(self, x, b):
 
1286
        xb = arr(x**b)
 
1287
        return 1.0-exp(1-exp(xb))
 
1288
    def _ppf(self, q, b):
 
1289
        return pow(log(1.0-log(1.0-q)), 1.0/b)
 
1290
exponpow = exponpow_gen(a=0.0,name='exponpow',longname="An exponential power",
 
1291
                        shapes='b',extradoc="""
 
1292
 
 
1293
Exponential Power distribution
 
1294
"""
 
1295
                        )
 
1296
 
 
1297
## Faigue-Life (Birnbaum-Sanders)
 
1298
class fatiguelife_gen(rv_continuous):
 
1299
    def _rvs(self, c):
 
1300
        z = norm.rvs(size=self._size)
 
1301
        U = random(size=self._size)
 
1302
        fac = 2 + c*c*z*z
 
1303
        det = sqrt(fac*fac - 4)
 
1304
        t1 = fac + det
 
1305
        t2 = fac - det
 
1306
        return t1*(U>0.5) + t2*(U<0.5)        
 
1307
    def _pdf(self, x, c):
 
1308
        return (x+1)/arr(2*c*sqrt(2*pi*x**3))*exp(-(x-1)**2/arr((2.0*x*c**2)))
 
1309
    def _cdf(self, x, c):
 
1310
        return special.ndtr(1.0/c*(sqrt(x)-1.0/arr(sqrt(x))))
 
1311
    def _ppf(self, q, c):
 
1312
        tmp = c*special.ndtri(q)
 
1313
        return 0.25*(tmp + sqrt(tmp**2 + 4))**2
 
1314
    def _stats(self, c):
 
1315
        c2 = c*c
 
1316
        mu = c2 / 2.0 + 1
 
1317
        den = 5*c2 + 4
 
1318
        mu2 = c2*den /4.0
 
1319
        g1 = 4*c*sqrt(11*c2+6.0)/den**1.5
 
1320
        g2 = 6*c2*(93*c2+41.0) / den**2.0
 
1321
        return mu, mu2, g1, g2
 
1322
fatiguelife = fatiguelife_gen(a=0.0,name='fatiguelife',
 
1323
                              longname="A fatigue-life (Birnbaum-Sanders)",
 
1324
                              shapes='c',extradoc="""
 
1325
 
 
1326
Fatigue-life (Birnbaum-Sanders) distribution
 
1327
"""
 
1328
                              )
 
1329
 
 
1330
## Folded Cauchy
 
1331
 
 
1332
class foldcauchy_gen(rv_continuous):
 
1333
    def _rvs(self, c):
 
1334
        return abs(cauchy.rvs(loc=c,size=self._size))
 
1335
    def _pdf(self, x, c):
 
1336
        return 1.0/pi*(1.0/(1+(x-c)**2) + 1.0/(1+(x+c)**2))
 
1337
    def _cdf(self, x, c):
 
1338
        return 1.0/pi*(arctan(x-c) + arctan(x+c))
 
1339
    def _stats(self, x, c):
 
1340
        return inf, inf, nan, nan
 
1341
foldcauchy = foldcauchy_gen(a=0.0, name='foldcauchy',
 
1342
                            longname = "A folded Cauchy",
 
1343
                            shapes='c',extradoc="""
 
1344
 
 
1345
A folded Cauchy distributions
 
1346
"""
 
1347
                            )
 
1348
        
 
1349
## F
 
1350
 
 
1351
class f_gen(rv_continuous):
 
1352
    def _rvs(self, dfn, dfd):
 
1353
        return rand.f(dfn, dfd, self._size)
 
1354
    def _pdf(self, x, dfn, dfd):
 
1355
        n = arr(1.0*dfn)
 
1356
        m = arr(1.0*dfd)
 
1357
        Px = m**(m/2) * n**(n/2) * x**(n/2-1)
 
1358
        Px /= (m+n*x)**((n+m)/2)*special.beta(n/2,m/2)
 
1359
        return Px
 
1360
    def _cdf(self, x, dfn, dfd):
 
1361
        return special.fdtr(dfn, dfd, x)
 
1362
    def _sf(self, x, dfn, dfd):
 
1363
        return special.fdtrc(dfn, dfd, x)
 
1364
    def _ppf(self, q, dfn, dfd):
 
1365
        return special.fdtri(dfn, dfd, q)        
 
1366
    def _stats(self, dfn, dfd):
 
1367
        v2 = arr(dfd*1.0)
 
1368
        v1 = arr(dfn*1.0)
 
1369
        mu = where (v2 > 2, v2 / arr(v2 - 2), inf)
 
1370
        mu2 = 2*v2*v2*(v2+v1-2)/(v1*(v2-2)**2 * (v2-4))
 
1371
        mu2 = where(v2 > 4, mu2, inf)
 
1372
        g1 = 2*(v2+2*v1-2)/(v2-6)*sqrt((2*v2-4)/(v1*(v2+v1-2)))
 
1373
        g1 = where(v2 > 6, g1, nan)
 
1374
        g2 = 3/(2*v2-16)*(8+g1*g1*(v2-6))
 
1375
        g2 = where(v2 > 8, g2, nan)
 
1376
        return mu, mu2, g1, g2
 
1377
f = f_gen(a=0.0,name='f',longname='An F',shapes="dfn,dfd",
 
1378
          extradoc="""
 
1379
 
 
1380
F distribution
 
1381
"""
 
1382
          )
 
1383
 
 
1384
## Folded Normal  
 
1385
##   abs(Z) where (Z is normal with mu=L and std=S so that c=abs(L)/S)
 
1386
##
 
1387
##  note: regress docs have scale parameter correct, but first parameter
 
1388
##    he gives is a shape parameter A = c * scale
 
1389
 
 
1390
##  Half-normal is folded normal with shape-parameter c=0.
 
1391
 
 
1392
class foldnorm_gen(rv_continuous):
 
1393
    def _rvs(self, c):
 
1394
        return abs(norm.rvs(loc=c,size=self._size))
 
1395
    def _pdf(self, x, c):
 
1396
        return sqrt(2.0/pi)*cosh(c*x)*exp(-(x*x+c*c)/2.0)
 
1397
    def _cdf(self, x, c,):
 
1398
        return special.ndtr(x-c) + special.ndtr(x+c) - 1.0
 
1399
    def _stats(self, c):
 
1400
        fac = special.erf(c/sqrt(2))
 
1401
        mu = sqrt(2.0/pi)*exp(-0.5*c*c)+c*fac
 
1402
        mu2 = c*c + 1 - mu*mu
 
1403
        c2 = c*c
 
1404
        g1 = sqrt(2/pi)*exp(-1.5*c2)*(4-pi*exp(c2)*(2*c2+1.0))
 
1405
        g1 += 2*c*fac*(6*exp(-c2) + 3*sqrt(2*pi)*c*exp(-c2/2.0)*fac + \
 
1406
                       pi*c*(fac*fac-1))
 
1407
        g1 /= pi*mu2**1.5
 
1408
    
 
1409
        g2 = c2*c2+6*c2+3+6*(c2+1)*mu*mu - 3*mu**4
 
1410
        g2 -= 4*exp(-c2/2.0)*mu*(sqrt(2.0/pi)*(c2+2)+c*(c2+3)*exp(c2/2.0)*fac)
 
1411
        g2 /= mu2**2.0
 
1412
        return mu, mu2, g1, g2
 
1413
foldnorm = foldnorm_gen(a=0.0,name='foldnorm',longname='A folded normal',
 
1414
                        shapes='c',extradoc="""
 
1415
 
 
1416
Folded normal distribution
 
1417
"""
 
1418
                        )
 
1419
 
 
1420
## Extreme Value Type II or Frechet
 
1421
## (defined in Regress+ documentation as Extreme LB) as
 
1422
##   a limiting value distribution.
 
1423
##
 
1424
class frechet_r_gen(rv_continuous):
 
1425
    def _pdf(self, x, c):
 
1426
        return c*pow(x,c-1)*exp(-pow(x,c))
 
1427
    def _cdf(self, x, c):
 
1428
        return 1-exp(-pow(x,c))
 
1429
    def _ppf(self, q, c):
 
1430
        return pow(-log(1-q),1.0/c)
 
1431
    def _munp(self, n, c):
 
1432
        return special.gamma(1.0+n*1.0/c)
 
1433
    def _entropy(self, c):
 
1434
        return -_EULER / c - log(c) + _EULER + 1
 
1435
frechet_r = frechet_r_gen(a=0.0,name='frechet_r',longname="A Frechet right",
 
1436
                          shapes='c',extradoc="""
 
1437
 
 
1438
A Frechet (right) distribution (also called Weibull minimum)
 
1439
"""
 
1440
                          )
 
1441
weibull_min = frechet_r_gen(a=0.0,name='weibull_min',
 
1442
                            longname="A Weibull minimum",
 
1443
                            shapes='c',extradoc="""
 
1444
 
 
1445
A Weibull minimum distribution
 
1446
"""
 
1447
                            )
 
1448
 
 
1449
class frechet_l_gen(rv_continuous):
 
1450
    def _pdf(self, x, c):
 
1451
        return c*pow(-x,c-1)*exp(-pow(-x,c))
 
1452
    def _cdf(self, x, c):
 
1453
        return exp(-pow(-x,c))
 
1454
    def _ppf(self, q, c):
 
1455
        return -pow(-log(q),1.0/c)
 
1456
    def _munp(self, n, c):
 
1457
        val = special.gamma(1.0+n*1.0/c)
 
1458
        if (int(n) % 2): sgn = -1
 
1459
        else:            sgn = 1
 
1460
        return sgn*val
 
1461
    def _entropy(self, c):
 
1462
        return -_EULER / c - log(c) + _EULER + 1    
 
1463
frechet_l = frechet_l_gen(b=0.0,name='frechet_l',longname="A Frechet left",
 
1464
                          shapes='c',extradoc="""
 
1465
 
 
1466
A Frechet (left) distribution (also called Weibull maximum)
 
1467
"""
 
1468
                          )
 
1469
weibull_max = frechet_l_gen(b=0.0,name='weibull_max',
 
1470
                            longname="A Weibull maximum",
 
1471
                            shapes='c',extradoc="""
 
1472
 
 
1473
A Weibull maximum distribution
 
1474
"""
 
1475
                            )
 
1476
 
 
1477
 
 
1478
## Generalized Logistic
 
1479
##
 
1480
class genlogistic_gen(rv_continuous):
 
1481
    def _pdf(self, x, c):
 
1482
        Px = c*exp(-x)/(1+exp(-x))**(c+1.0)
 
1483
        return Px
 
1484
    def _cdf(self, x, c):
 
1485
        Cx = (1+exp(-x))**(-c)
 
1486
        return Cx
 
1487
    def _ppf(self, q, c):
 
1488
        vals = -log(pow(q,-1.0/c)-1)
 
1489
        return vals
 
1490
    def _stats(self, c):
 
1491
        zeta = special.zeta
 
1492
        mu = _EULER + special.psi(c)
 
1493
        mu2 = pi*pi/6.0 + zeta(2,c)
 
1494
        g1 = -2*zeta(3,c) + 2*_ZETA3
 
1495
        g1 /= mu2**1.5
 
1496
        g2 = pi**4/15.0 + 6*zeta(4,c)
 
1497
        g2 /= mu2**2.0
 
1498
        return mu, mu2, g1, g2
 
1499
genlogistic = genlogistic_gen(name='genlogistic',
 
1500
                              longname="A generalized logistic",
 
1501
                              shapes='c',extradoc="""
 
1502
 
 
1503
Generalized logistic distribution
 
1504
"""
 
1505
                              )
 
1506
 
 
1507
## Generalized Pareto
 
1508
class genpareto_gen(rv_continuous):
 
1509
    def _argcheck(self, c):
 
1510
        c = arr(c)
 
1511
        self.b = where(c < 0, 1.0/abs(c), inf)
 
1512
        return where(c==0, 0, 1)
 
1513
    def _pdf(self, x, c):
 
1514
        Px = pow(1+c*x,arr(-1.0-1.0/c))
 
1515
        return Px
 
1516
    def _cdf(self, x, c):
 
1517
        return 1.0 - pow(1+c*x,arr(-1.0/c))
 
1518
    def _ppf(self, q, c):
 
1519
        vals = 1.0/c * (pow(1-q, -c)-1)
 
1520
        return vals
 
1521
    def _munp(self, n, c):
 
1522
        k = arange(0,n+1)
 
1523
        val = (-1.0/c)**n * sum(scipy.comb(n,k)*(-1)**k / (1.0-c*k))
 
1524
        return where(c*n < 1, val, inf)
 
1525
    def _entropy(self, c):
 
1526
        if (c > 0):
 
1527
            return 1+c
 
1528
        else:
 
1529
            self.b = -1.0 / c
 
1530
            return rv_continuous._entropy(self, c)
 
1531
genpareto = genpareto_gen(a=0.0,name='genpareto',
 
1532
                          longname="A generalized Pareto",
 
1533
                          shapes='c',extradoc="""
 
1534
 
 
1535
Generalized Pareto distribution
 
1536
"""                          
 
1537
                          )
 
1538
 
 
1539
## Generalized Exponential
 
1540
 
 
1541
class genexpon_gen(rv_continuous):
 
1542
    def _pdf(self, x, a, b, c):
 
1543
        return (a+b*(1-exp(-c*x)))*exp((a-b)*x+b*(1-exp(-c*x))/c)
 
1544
    def _cdf(self, x, a, b, c):
 
1545
        return 1.0-exp((a-b)*x + b*(1-exp(-c*x))/c)
 
1546
genexpon = genexpon_gen(a=0.0,name='genexpon',
 
1547
                        longname='A generalized exponential',
 
1548
                        shapes='a,b,c',extradoc="""
 
1549
 
 
1550
Generalized exponential distribution
 
1551
"""
 
1552
                        )
 
1553
 
 
1554
## Generalized Extreme Value
 
1555
##  c=0 is just gumbel distribution.
 
1556
##  This version does not accept c==0
 
1557
##  Use gumbel_r for c==0
 
1558
 
 
1559
class genextreme_gen(rv_continuous):
 
1560
    def _argcheck(self, c):
 
1561
        self.b = where(c > 0, 1.0 / c, inf)
 
1562
        self.a = where(c < 0, 1.0 / c, -inf)
 
1563
        return (c!=0)
 
1564
    def _pdf(self, x, c):
 
1565
        ex2 = 1-c*x
 
1566
        pex2 = pow(ex2,1.0/c)
 
1567
        p2 = exp(-pex2)*pex2/ex2
 
1568
        return p2
 
1569
    def _cdf(self, x, c):
 
1570
        return exp(-pow(1-c*x,1.0/c))
 
1571
    def _ppf(self, q, c):
 
1572
        return 1.0/c*(1-(-log(q))**c)
 
1573
    def _munp(self, n, c):
 
1574
        k = arange(0,n+1)
 
1575
        vals = 1.0/c**n * sum(scipy.comb(n,k) * (-1)**k * special.gamma(c*k + 1))
 
1576
        return where(c*n > -1, vals, inf)
 
1577
genextreme = genextreme_gen(name='genextreme',
 
1578
                            longname="A generalized extreme value",
 
1579
                            shapes='c',extradoc="""
 
1580
 
 
1581
Generalized extreme value (see gumbel_r for c=0)
 
1582
"""
 
1583
                            )
 
1584
        
 
1585
## Gamma (Use MATLAB and MATHEMATICA (b=theta=scale, a=alpha=shape) definition)
 
1586
 
 
1587
## gamma(a, loc, scale)  with a an integer is the Erlang distribution
 
1588
## gamma(1, loc, scale)  is the Exponential distribution
 
1589
## gamma(df/2, 0, 2) is the chi2 distribution with df degrees of freedom.
 
1590
 
 
1591
class gamma_gen(rv_continuous):
 
1592
    def _rvs(self, a):
 
1593
        return rand.standard_gamma(a, self._size)
 
1594
    def _pdf(self, x, a):
 
1595
        return x**(a-1)*exp(-x)/special.gamma(a)
 
1596
    def _cdf(self, x, a):
 
1597
        return special.gammainc(a, x)
 
1598
    def _ppf(self, q, a):
 
1599
        return special.gammaincinv(a,q)
 
1600
    def _stats(self, a):
 
1601
        return a, a, 2.0/sqrt(a), 6.0/a
 
1602
    def _entropy(self, a):
 
1603
        return special.psi(a)*(1-a) + 1 + special.gammaln(a)
 
1604
gamma = gamma_gen(a=0.0,name='gamma',longname='A gamma',
 
1605
                  shapes='a',extradoc="""
 
1606
 
 
1607
Gamma distribution
 
1608
"""
 
1609
                  )
 
1610
 
 
1611
# Generalized Gamma
 
1612
class gengamma_gen(rv_continuous):
 
1613
    def _argcheck(self, a, c):
 
1614
        return (a > 0) & (c != 0)
 
1615
    def _pdf(self, x, a, c):
 
1616
        return abs(c)* x**(c*a-1) / special.gamma(a) * exp(-x**c)
 
1617
    def _cdf(self, x, a, c):
 
1618
        val = special.gammainc(a,x**c)
 
1619
        cond = c + 0*val
 
1620
        return where(cond>0,val,1-val)
 
1621
    def _ppf(self, q, a, c):
 
1622
        val1 = special.gammaincinv(a,q)
 
1623
        val2 = special.gammaincinv(a,1.0-q)
 
1624
        ic = 1.0/c
 
1625
        cond = c+0*val1
 
1626
        return where(cond > 0,val1**ic,val2**ic)
 
1627
    def _munp(self, n, a, c):
 
1628
        return special.gamma(a+n*1.0/c) / special.gamma(a)
 
1629
    def _entropy(a,c):
 
1630
        val = special.psi(a)
 
1631
        return a*(1-val) + 1.0/c*val + special.gammaln(a)-log(abs(c))
 
1632
gengamma = gengamma_gen(a=0.0, name='gengamma',
 
1633
                        longname='A generalized gamma',
 
1634
                        shapes="a,c", extradoc="""
 
1635
 
 
1636
Generalized gamma distribution
 
1637
"""
 
1638
                        )
 
1639
 
 
1640
##  Generalized Half-Logistic
 
1641
##
 
1642
 
 
1643
class genhalflogistic_gen(rv_continuous):
 
1644
    def _argcheck(self, c):
 
1645
        self.b = 1.0 / c
 
1646
        return (c > 0)
 
1647
    def _pdf(self, x, c):
 
1648
        limit = 1.0/c
 
1649
        tmp = arr(1-c*x)
 
1650
        tmp0 = tmp**(limit-1)
 
1651
        tmp2 = tmp0*tmp
 
1652
        return 2*tmp0 / (1+tmp2)**2
 
1653
    def _cdf(self, x, c):
 
1654
        limit = 1.0/c
 
1655
        tmp = arr(1-c*x)
 
1656
        tmp2 = tmp**(limit)
 
1657
        return (1.0-tmp2) / (1+tmp2)
 
1658
    def _ppf(self, q, c):
 
1659
        return 1.0/c*(1-((1.0-q)/(1.0+q))**c)
 
1660
    def _entropy(self,c):
 
1661
        return 2 - (2*c+1)*log(2)
 
1662
genhalflogistic = genhalflogistic_gen(a=0.0, name='genhalflogistic',
 
1663
                                      longname="A generalized half-logistic",
 
1664
                                      shapes='c',extradoc="""
 
1665
 
 
1666
Generalized half-logistic
 
1667
"""
 
1668
                                      )
 
1669
 
 
1670
## Gompertz (Truncated Gumbel)
 
1671
##  Defined for x>=0
 
1672
 
 
1673
class gompertz_gen(rv_continuous):
 
1674
    def _pdf(self, x, c):
 
1675
        ex = exp(x)
 
1676
        return c*ex*exp(-c*(ex-1))
 
1677
    def _cdf(self, x, c):
 
1678
        return 1.0-exp(-c*(exp(x)-1))
 
1679
    def _ppf(self, q, c):
 
1680
        return log(1-1.0/c*log(1-q))
 
1681
    def _entropy(self, c):
 
1682
        return 1.0 - log(c) - exp(c)*special.expn(1,c)
 
1683
gompertz = gompertz_gen(a=0.0, name='gompertz',
 
1684
                        longname="A Gompertz (truncated Gumbel) distribution",
 
1685
                        shapes='c',extradoc="""
 
1686
 
 
1687
Gompertz (truncated Gumbel) distribution
 
1688
"""
 
1689
                        )
 
1690
    
 
1691
## Gumbel, Log-Weibull, Fisher-Tippett, Gompertz
 
1692
## The left-skewed gumbel distribution.
 
1693
## and right-skewed are available as gumbel_l  and gumbel_r
 
1694
 
 
1695
class gumbel_r_gen(rv_continuous):
 
1696
    def _pdf(self, x):
 
1697
        ex = exp(-x)
 
1698
        return ex*exp(-ex)
 
1699
    def _cdf(self, x):
 
1700
        return exp(-exp(-x))
 
1701
    def _ppf(self, q):
 
1702
        return -log(-log(q))
 
1703
    def _stats(self):
 
1704
        return _EULER, pi*pi/6.0, \
 
1705
               12*sqrt(6)/pi**3 * _ZETA3, 12.0/5
 
1706
    def _entropy(self):
 
1707
        return 1.0608407169541684911
 
1708
gumbel_r = gumbel_r_gen(name='gumbel_r',longname="A (right-skewed) Gumbel",
 
1709
                        extradoc="""
 
1710
 
 
1711
Right-skewed Gumbel (Log-Weibull, Fisher-Tippett, Gompertz) distribution
 
1712
"""
 
1713
                        )
 
1714
class gumbel_l_gen(rv_continuous):
 
1715
    def _pdf(self, x):
 
1716
        ex = exp(x)
 
1717
        return ex*exp(-ex)
 
1718
    def _cdf(self, x):
 
1719
        return 1.0-exp(-exp(x))
 
1720
    def _ppf(self, q):
 
1721
        return log(-log(1-q))
 
1722
    def _stats(self):
 
1723
        return _EULER, pi*pi/6.0, \
 
1724
               12*sqrt(6)/pi**3 * _ZETA3, 12.0/5
 
1725
    def _entropy(self):
 
1726
        return 1.0608407169541684911
 
1727
gumbel_l = gumbel_l_gen(name='gumbel_l',longname="A left-skewed Gumbel",
 
1728
                        extradoc="""
 
1729
 
 
1730
Left-skewed Gumbel distribution
 
1731
"""
 
1732
                        )
 
1733
 
 
1734
# Half-Cauchy
 
1735
 
 
1736
class halfcauchy_gen(rv_continuous):
 
1737
    def _pdf(self, x):
 
1738
        return 2.0/pi/(1.0+x*x)
 
1739
    def _cdf(self, x):
 
1740
        return 2.0/pi*arctan(x)
 
1741
    def _ppf(self, q):
 
1742
        return tan(pi/2*q)
 
1743
    def _stats(self):
 
1744
        return inf, inf, nan, nan
 
1745
    def _entropy(self):
 
1746
        return log(2*pi)
 
1747
halfcauchy = halfcauchy_gen(a=0.0,name='halfcauchy',
 
1748
                            longname="A Half-Cauchy",extradoc="""
 
1749
 
 
1750
Half-Cauchy distribution
 
1751
"""
 
1752
                            )
 
1753
 
 
1754
 
 
1755
## Half-Logistic
 
1756
##  
 
1757
 
 
1758
class halflogistic_gen(rv_continuous):
 
1759
    def _pdf(self, x):
 
1760
        return 0.5/(cosh(x/2.0))**2.0
 
1761
    def _cdf(self, x):
 
1762
        return tanh(x/2.0)
 
1763
    def _ppf(self, q):
 
1764
        return 2*arctanh(q)
 
1765
    def _munp(self, n):
 
1766
        if n==1: return 2*log(2)
 
1767
        if n==2: return pi*pi/3.0
 
1768
        if n==3: return 9*_ZETA3
 
1769
        if n==4: return 7*pi**4 / 15.0
 
1770
        return 2*(1-pow(2.0,1-n))*special.gamma(n+1)*special.zeta(n,1)
 
1771
    def _entropy(self):
 
1772
        return 2-log(2)
 
1773
halflogistic = halflogistic_gen(a=0.0, name='halflogistic',
 
1774
                                longname="A half-logistic",
 
1775
                                extradoc="""
 
1776
 
 
1777
Half-logistic distribution                                
 
1778
"""
 
1779
                                )
 
1780
 
 
1781
 
 
1782
## Half-normal = chi(1, loc, scale)
 
1783
 
 
1784
class halfnorm_gen(rv_continuous):
 
1785
    def _rvs(self):
 
1786
        return abs(norm.rvs(size=self._size))
 
1787
    def _pdf(self, x):
 
1788
        return sqrt(2.0/pi)*exp(-x*x/2.0)
 
1789
    def _cdf(self, x):
 
1790
        return special.ndtr(x)*2-1.0
 
1791
    def _ppf(self, q):
 
1792
        return special.ndtri((1+q)/2.0)
 
1793
    def _stats(self):
 
1794
        return sqrt(2.0/pi), 1-2.0/pi, sqrt(2)*(4-pi)/(pi-2)**1.5, \
 
1795
               8*(pi-3)/(pi-2)**2
 
1796
    def _entropy(self):
 
1797
        return 0.5*log(pi/2.0)+0.5
 
1798
halfnorm = halfnorm_gen(a=0.0, name='halfnorm',
 
1799
                        longname="A half-normal",
 
1800
                        extradoc="""
 
1801
                        
 
1802
Half-normal distribution
 
1803
"""                        
 
1804
                        )
 
1805
 
 
1806
## Hyperbolic Secant
 
1807
 
 
1808
class hypsecant_gen(rv_continuous):
 
1809
    def _pdf(self, x):
 
1810
        return 1.0/(pi*cosh(x))
 
1811
    def _cdf(self, x):
 
1812
        return 2.0/pi*arctan(exp(x))
 
1813
    def _ppf(self, q):
 
1814
        return log(tan(pi*q/2.0))
 
1815
    def _stats(self):
 
1816
        return 0, pi*pi/4, 0, 2
 
1817
    def _entropy(self):
 
1818
        return log(2*pi)
 
1819
hypsecant = hypsecant_gen(name='hypsecant',longname="A hyperbolic secant",
 
1820
                          extradoc="""
 
1821
 
 
1822
Hyperbolic secant distribution
 
1823
"""
 
1824
                          )
 
1825
 
 
1826
## Gauss Hypergeometric
 
1827
 
 
1828
class gausshyper_gen(rv_continuous):
 
1829
    def _argcheck(self, a, b, c, z):
 
1830
        return (a > 0) & (b > 0) & (c==c) & (z==z)
 
1831
    def _pdf(self, x, a, b, c, z):
 
1832
        Cinv = gam(a)*gam(b)/gam(a+b)*special.hyp2f1(c,a,a+b,-z)
 
1833
        return 1.0/Cinv * x**(a-1.0) * (1.0-x)**(b-1.0) / (1.0+z*x)**c
 
1834
    def _munp(self, n, a, b, c, z):
 
1835
        fac = special.beta(n+a,b) / special.beta(a,b)
 
1836
        num = special.hyp2f1(c,a+n,a+b+n,-z)
 
1837
        den = special.hyp2f1(c,a,a+b,-z)
 
1838
        return fac*num / den
 
1839
gausshyper = gausshyper_gen(a=0.0, b=1.0, name='gausshyper',
 
1840
                            longname="A Gauss hypergeometric",
 
1841
                            shapes="a,b,c,z",
 
1842
                            extradoc="""
 
1843
 
 
1844
Gauss hypergeometric distribution
 
1845
"""
 
1846
                            )
 
1847
 
 
1848
##  Inverted Gamma
 
1849
#     special case of generalized gamma with c=-1
 
1850
#
 
1851
 
 
1852
class invgamma_gen(rv_continuous):
 
1853
    def _pdf(self, x, a):
 
1854
        return x**(-a-1) / special.gamma(a) * exp(-1.0/x)
 
1855
    def _cdf(self, x, a):
 
1856
        return 1.0-special.gammainc(a, 1.0/x)
 
1857
    def _ppf(self, q, a):
 
1858
        return 1.0/special.gammaincinv(a,1-q)
 
1859
    def _munp(self, n, a):
 
1860
        return special.gamma(a-n) / special.gamma(a)
 
1861
    def _entropy(self, a):
 
1862
        return a - (a+1.0)*special.psi(a) + special.gammaln(a)
 
1863
invgamma = invgamma_gen(a=0.0, name='invgamma',longname="An inverted gamma",
 
1864
                        shapes='a',extradoc="""
 
1865
 
 
1866
Inverted gamma distribution
 
1867
"""
 
1868
                        )
 
1869
 
 
1870
 
 
1871
## Inverse Normal Distribution
 
1872
# scale is gamma from DATAPLOT and B from Regress
 
1873
 
 
1874
class invnorm_gen(rv_continuous):
 
1875
    def _rvs(self, mu):
 
1876
        return rv._inst._Wald(mu,size=(self._size,))
 
1877
    def _pdf(self, x, mu):
 
1878
        return 1.0/sqrt(2*pi*x**3.0)*exp(-1.0/(2*x)*((x-mu)/mu)**2)
 
1879
    def _cdf(self, x, mu):
 
1880
        fac = sqrt(1.0/x)
 
1881
        C1 = norm.cdf(fac*(x-mu)/mu)
 
1882
        C1 += exp(2.0/mu)*norm.cdf(-fac*(x+mu)/mu)
 
1883
        return C1
 
1884
    def _stats(self, mu):
 
1885
        return mu, mu**3.0, 3*sqrt(mu), 15*mu
 
1886
invnorm = invnorm_gen(a=0.0, name='invnorm', longname="An inverse normal",
 
1887
                      shapes="mu",extradoc="""
 
1888
 
 
1889
Inverse normal distribution
 
1890
"""
 
1891
                      )
 
1892
 
 
1893
## Inverted Weibull
 
1894
 
 
1895
class invweibull_gen(rv_continuous):
 
1896
    def _pdf(self, x, c):
 
1897
        xc1 = x**(-c-1.0)
 
1898
        xc2 = xc1*x
 
1899
        return c*xc1*xc2
 
1900
    def _cdf(self, x, c):
 
1901
        xc1 = x**(-c)
 
1902
        return exp(-xc1)
 
1903
    def _ppf(self, q, c):
 
1904
        return pow(-log(q),arr(-1.0/c))
 
1905
    def _entropy(self, c):
 
1906
        return 1+_EULER + _EULER / c - log(c)
 
1907
invweibull = invweibull_gen(a=0,name='invweibull',
 
1908
                            longname="An inverted Weibull",
 
1909
                            shapes='c',extradoc="""
 
1910
 
 
1911
Inverted Weibull distribution
 
1912
"""
 
1913
                            )
 
1914
 
 
1915
## Johnson SB
 
1916
 
 
1917
class johnsonsb_gen(rv_continuous):
 
1918
    def _argcheck(self, a, b):
 
1919
        return (b > 0) & (a==a)
 
1920
    def _pdf(self, x, a, b):
 
1921
        trm = norm.pdf(a+b*log(x/(1.0-x)))
 
1922
        return b*1.0/(x*(1-x))*trm
 
1923
    def _cdf(self, x, a, b):
 
1924
        return norm.cdf(a+b*log(x/(1.0-x)))
 
1925
    def _ppf(self, q, a, b):
 
1926
        return 1.0/(1+exp(-1.0/b*norm.ppf(q)-a))
 
1927
johnsonsb = johnsonsb_gen(a=0.0,b=1.0,name='johnsonb',
 
1928
                          longname="A Johnson SB",
 
1929
                          shapes="a,b",extradoc="""
 
1930
 
 
1931
Johnson SB distribution
 
1932
"""
 
1933
                          )
 
1934
 
 
1935
## Johnson SU
 
1936
class johnsonsu_gen(rv_continuous):
 
1937
    def _argcheck(self, a, b):
 
1938
        return (b > 0) & (a==a)
 
1939
    def _pdf(self, x, a, b):
 
1940
        x2 = x*x
 
1941
        trm = norm.pdf(a+b*log(x+sqrt(x2+1)))
 
1942
        return b*1.0/sqrt(x2+1.0)*trm
 
1943
    def _cdf(self, x, a, b):
 
1944
        return norm.cdf(a+b*log(x+sqrt(x*x+1)))
 
1945
    def _ppf(self, q, a, b):
 
1946
        return sinh((norm.ppf(q)-a)/b)
 
1947
johnsonsu = johnsonsu_gen(name='johnsonsu',longname="A Johnson SU",
 
1948
                          shapes="a,b", extradoc="""
 
1949
 
 
1950
Johnson SB distribution
 
1951
"""
 
1952
                          )
 
1953
 
 
1954
 
 
1955
## Laplace Distribution
 
1956
 
 
1957
class laplace_gen(rv_continuous):
 
1958
    def _pdf(self, x):
 
1959
        return 0.5*exp(-abs(x))
 
1960
    def _cdf(self, x):
 
1961
        return where(x > 0, 1.0-0.5*exp(-x), 0.5*exp(x))
 
1962
    def _ppf(self, q):
 
1963
        return where(q > 0.5, -log(2*(1-q)), log(2*q))
 
1964
    def _stats(self):
 
1965
        return 0, 2, 0, 3
 
1966
    def _entropy(self):
 
1967
        return log(2)+1
 
1968
laplace = laplace_gen(name='laplace', longname="A Laplace",
 
1969
                      extradoc="""
 
1970
 
 
1971
Laplacian distribution
 
1972
"""
 
1973
                      )
 
1974
 
 
1975
 
 
1976
## Levy Distribution
 
1977
 
 
1978
class levy_gen(rv_continuous):
 
1979
    def _pdf(self, x):
 
1980
        return 1/sqrt(2*x)/x*exp(-1/(2*x))
 
1981
    def _cdf(self, x):
 
1982
        return 2*(1-norm._cdf(1/sqrt(x)))
 
1983
    def _ppf(self, q):
 
1984
        val = norm._ppf(1-q/2.0)
 
1985
        return 1.0/(val*val)
 
1986
    def _stats(self):
 
1987
        return inf, inf, nan, nan
 
1988
levy = levy_gen(a=0.0,name="levy", longname = "A Levy", extradoc="""
 
1989
 
 
1990
Levy distribution
 
1991
"""
 
1992
                )
 
1993
 
 
1994
## Left-skewed Levy Distribution
 
1995
 
 
1996
class levy_l_gen(rv_continuous):
 
1997
    def _pdf(self, x):
 
1998
        ax = abs(x)
 
1999
        return 1/sqrt(2*ax)/ax*exp(-1/(2*ax))
 
2000
    def _cdf(self, x):
 
2001
        ax = abs(x)
 
2002
        return 2*norm._cdf(1/sqrt(ax))-1
 
2003
    def _ppf(self, q):
 
2004
        val = norm._ppf((q+1.0)/2)
 
2005
        return -1.0/(val*val)
 
2006
    def _stats(self):
 
2007
        return inf, inf, nan, nan
 
2008
levy_l = levy_l_gen(b=0.0,name="levy_l", longname = "A left-skewed Levy", extradoc="""
 
2009
 
 
2010
Left-skewed Levy distribution
 
2011
"""
 
2012
                )
 
2013
 
 
2014
## Levy-stable Distribution (only random variates)
 
2015
 
 
2016
class levy_stable_gen(rv_continuous):
 
2017
    def _rvs(self, alpha, beta):
 
2018
        sz = self._size
 
2019
        TH = uniform.rvs(loc=-pi/2.0,scale=pi,size=sz)
 
2020
        W = expon.rvs(size=sz)
 
2021
        if alpha==1:
 
2022
            return 2/pi*(pi/2+beta*TH)*tan(TH)-beta*log((pi/2*W*cos(TH))/(pi/2+beta*TH))
 
2023
        # else
 
2024
        ialpha = 1.0/alpha
 
2025
        aTH = alpha*TH
 
2026
        if beta==0:
 
2027
            return W/(cos(TH)/tan(aTH)+sin(TH))*((cos(aTH)+sin(aTH)*tan(TH))/W)**ialpha
 
2028
        # else
 
2029
        val0 = beta*tan(pi*alpha/2)
 
2030
        th0 = arctan(val0)/alpha
 
2031
        val3 = W/(cos(TH)/tan(alpha*(th0+TH))+sin(TH))
 
2032
        res3 = val3*((cos(aTH)+sin(aTH)*tan(TH)-val0*(sin(aTH)-cos(aTH)*tan(TH)))/W)**ialpha
 
2033
        return res3
 
2034
        
 
2035
    def _argcheck(self, alpha, beta):        
 
2036
        if beta == -1:
 
2037
            self.b = 0.0
 
2038
        elif beta == 1:
 
2039
            self.a = 0.0
 
2040
        return (alpha > 0) & (alpha <= 2) & (beta <= 1) & (beta >= -1)
 
2041
    
 
2042
    def _pdf(self, x, alpha, beta):
 
2043
        raise NotImplementedError
 
2044
 
 
2045
levy_stable = levy_stable_gen(name='levy_stable', longname="A Levy-stable",
 
2046
                    shapes="alpha, beta", extradoc="""
 
2047
 
 
2048
Levy-stable distribution (only random variates available -- ignore other docs)
 
2049
"""
 
2050
                    )
 
2051
    
 
2052
 
 
2053
## Logistic (special case of generalized logistic with c=1)
 
2054
## Sech-squared
 
2055
 
 
2056
class logistic_gen(rv_continuous):
 
2057
    def _pdf(self, x):
 
2058
        ex = exp(-x)
 
2059
        return ex / (1+ex)**2.0
 
2060
    def _cdf(self, x):
 
2061
        return 1.0/(1+exp(-x))
 
2062
    def _ppf(self, q):
 
2063
        return -log(1.0/q-1)
 
2064
    def _stats(self):
 
2065
        return 0, pi*pi/3.0, 0, 6.0/5.0
 
2066
    def _entropy(self):
 
2067
        return 1.0
 
2068
logistic = logistic_gen(name='logistic', longname="A logistic",
 
2069
                        extradoc="""
 
2070
 
 
2071
Logistic distribution
 
2072
"""
 
2073
                        )
 
2074
 
 
2075
 
 
2076
## Log Gamma
 
2077
#
 
2078
class loggamma_gen(rv_continuous):
 
2079
    def _pdf(self, x, c):
 
2080
        return exp(c*x-exp(x))/ special.gamma(c)
 
2081
    def _cdf(self, x, c):
 
2082
        return special.gammainc(c, exp(x))/ special.gamma(c)
 
2083
    def _ppf(self, q, c):
 
2084
        return log(special.gammaincinv(c,q*special.gamma(c)))
 
2085
loggamma = loggamma_gen(name='loggamma', longname="A log gamma",
 
2086
                        extradoc="""
 
2087
 
 
2088
Log gamma distribution
 
2089
"""
 
2090
                        )
 
2091
 
 
2092
## Log-Laplace  (Log Double Exponential)
 
2093
##
 
2094
 
 
2095
class loglaplace_gen(rv_continuous):
 
2096
    def _pdf(self, x, c):
 
2097
        cd2 = c/2.0
 
2098
        c = where(x < 1, c, -c)
 
2099
        return cd2*x**(c-1)
 
2100
    def _cdf(self, x, c):
 
2101
        return where(x < 1, 0.5*x**c, 1-0.5*x**(-c))
 
2102
    def _ppf(self, q, c):
 
2103
        return where(q < 0.5, (2.0*q)**(1.0/c), (2*(1.0-q))**(-1.0/c))
 
2104
    def _entropy(self, c):
 
2105
        return log(2.0/c) + 1.0
 
2106
loglaplace = loglaplace_gen(a=0.0, name='loglaplace',
 
2107
                            longname="A log-Laplace",shapes='c',
 
2108
                            extradoc="""
 
2109
 
 
2110
Log-Laplace distribution (Log Double Exponential)
 
2111
"""
 
2112
                            )
 
2113
 
 
2114
## Lognormal (Cobb-Douglass)
 
2115
## std is a shape parameter and is the variance of the underlying
 
2116
##    distribution.
 
2117
## the mean of the underlying distribution is log(scale)
 
2118
 
 
2119
class lognorm_gen(rv_continuous):
 
2120
    def _rvs(self, s):
 
2121
        return exp(s * norm.rvs(size=self._size))
 
2122
    def _pdf(self, x, s):
 
2123
        Px = exp(-log(x)**2 / (2*s**2))
 
2124
        return Px / (s*x*sqrt(2*pi))
 
2125
    def _cdf(self, x, s):
 
2126
        return norm.cdf(log(x)/s)
 
2127
    def _ppf(self, q, s):
 
2128
        return exp(s*norm._ppf(q))
 
2129
    def _stats(self, s):
 
2130
        p = exp(s*s)
 
2131
        mu = sqrt(p)
 
2132
        mu2 = p*(p-1)
 
2133
        g1 = sqrt((p-1))*(2+p)
 
2134
        g2 = scipy.polyval([1,2,3,0,-6.0],p)
 
2135
        return mu, mu2, g1, g2
 
2136
    def _entropy(self, s):
 
2137
        return 0.5*(1+log(2*pi)+2*log(s))
 
2138
lognorm = lognorm_gen(a=0.0, name='lognorm',
 
2139
                      longname='A lognormal', shapes='s',
 
2140
                      extradoc="""
 
2141
 
 
2142
Lognormal distribution
 
2143
"""
 
2144
                      )
 
2145
 
 
2146
# Gibrat's distribution is just lognormal with s=1
 
2147
 
 
2148
class gilbrat_gen(lognorm_gen):
 
2149
    def _rvs(self):
 
2150
        return lognorm_gen._rvs(self, 1.0)
 
2151
    def _pdf(self, x):
 
2152
        return lognorm_gen._pdf(self, x, 1.0)
 
2153
    def _cdf(self, x):
 
2154
        return lognorm_gen._cdf(self, x, 1.0)
 
2155
    def _ppf(self, q):
 
2156
        return lognorm_gen._ppf(self, q, 1.0)
 
2157
    def _stats(self):
 
2158
        return lognorm_gen._stats(self, 1.0)
 
2159
    def _entropy(self):
 
2160
        return 0.5*log(2*pi) + 0.5
 
2161
gilbrat = gilbrat_gen(a=0.0, name='gilbrat', longname='A Gilbrat',
 
2162
                      extradoc="""
 
2163
 
 
2164
Gilbrat distribution
 
2165
"""
 
2166
                      )
 
2167
 
 
2168
 
 
2169
# MAXWELL
 
2170
#  a special case of chi with df = 3, loc=0.0, and given scale = 1.0/sqrt(a)
 
2171
#    where a is the parameter used in mathworld description
 
2172
 
 
2173
class maxwell_gen(rv_continuous):
 
2174
    def _rvs(self):
 
2175
        return chi.rvs(3.0,size=self._size)
 
2176
    def _pdf(self, x):
 
2177
        return sqrt(2.0/pi)*x*x*exp(-x*x/2.0)
 
2178
    def _cdf(self, x):
 
2179
        return special.gammainc(1.5,x*x/2.0)
 
2180
    def _ppf(self, q):
 
2181
        return sqrt(2*special.gammaincinv(1.5,q))
 
2182
    def _stats(self):
 
2183
        val = 3*pi-8
 
2184
        return 2*sqrt(2.0/pi), 3-8/pi, sqrt(2)*(32-10*pi)/val**1.5, \
 
2185
               (-12*pi*pi + 160*pi - 384) / val**2.0
 
2186
    def _entropy(self):
 
2187
        return _EULER + 0.5*log(2*pi)-0.5
 
2188
maxwell = maxwell_gen(a=0.0, name='maxwell', longname="A Maxwell",
 
2189
                      extradoc="""
 
2190
 
 
2191
Maxwell distribution
 
2192
"""
 
2193
                      )
 
2194
 
 
2195
# Mielke's Beta-Kappa
 
2196
 
 
2197
class mielke_gen(rv_continuous):
 
2198
    def _pdf(self, x, k, s):
 
2199
        return k*x**(k-1.0) / (1.0+x**s)**(1.0+k*1.0/s)
 
2200
    def _cdf(self, x, k, s):
 
2201
        return x**k / (1.0+x**s)**(k*1.0/s)
 
2202
    def _ppf(self, q, k, s):
 
2203
        qsk = pow(q,s*1.0/k)
 
2204
        return pow(qsk/(1.0-qsk),1.0/s)
 
2205
mielke = mielke_gen(a=0.0, name='mielke', longname="A Mielke's Beta-Kappa",
 
2206
                    shapes="k,s", extradoc="""
 
2207
 
 
2208
Mielke's Beta-Kappa distribution
 
2209
"""
 
2210
                    )
 
2211
     
 
2212
# Nakagami (cf Chi)
 
2213
 
 
2214
class nakagami_gen(rv_continuous):
 
2215
    def _pdf(self, x, nu):
 
2216
        return 2*nu**nu/gam(nu)*(x**(2*nu-1.0))*exp(-nu*x*x)
 
2217
    def _cdf(self, x, nu):
 
2218
        return special.gammainc(nu,nu*x*x)
 
2219
    def _ppf(self, q, nu):
 
2220
        return sqrt(1.0/nu*special.gammaincinv(nu,q))
 
2221
    def _stats(self, nu):
 
2222
        mu = gam(nu+0.5)/gam(nu)/sqrt(nu)
 
2223
        mu2 = 1.0-mu*mu
 
2224
        g1 = mu*(1-4*nu*mu2)/2.0/nu/mu2**1.5
 
2225
        g2 = -6*mu**4*nu + (8*nu-2)*mu**2-2*nu + 1
 
2226
        g2 /= nu*mu2**2.0
 
2227
        return mu, mu2, g1, g2
 
2228
nakagami = nakagami_gen(a=0.0, name="nakagami", longname="A Nakagami",
 
2229
                        shapes='nu', extradoc="""
 
2230
 
 
2231
Nakagami distribution
 
2232
"""
 
2233
                        )
 
2234
    
 
2235
 
 
2236
# Non-central chi-squared
 
2237
# nc is lambda of definition, df is nu
 
2238
 
 
2239
class ncx2_gen(rv_continuous):
 
2240
    def _rvs(self, df, nc):
 
2241
        return rand.noncentral_chi2(df,nc,self._size)        
 
2242
    def _pdf(self, x, df, nc):
 
2243
        a = arr(df/2.0)
 
2244
        Px = exp(-nc/2.0)*special.hyp0f1(a,nc*x/4.0)
 
2245
        Px *= exp(-x/2.0)*x**(a-1) / arr(2**a * special.gamma(a))
 
2246
        return Px
 
2247
    def _cdf(self, x, df, nc):
 
2248
        return special.chndtr(x,df,nc)
 
2249
    def _ppf(self, q, df, nc):
 
2250
        return special.chndtrix(q,df,nc)
 
2251
    def _stats(self, df, nc):
 
2252
        val = df + 2.0*nc
 
2253
        return df + nc, 2*val, sqrt(8)*(val+nc)/val**1.5, \
 
2254
               12.0*(val+2*nc)/val**2.0
 
2255
ncx2 = ncx2_gen(a=0.0, name='ncx2', longname="A non-central chi-squared",
 
2256
                shapes="df,nc", extradoc="""
 
2257
 
 
2258
Non-central chi-squared distribution
 
2259
"""
 
2260
                )
 
2261
 
 
2262
# Non-central F
 
2263
 
 
2264
class ncf_gen(rv_continuous):
 
2265
    def _rvs(self, dfn, dfd, nc):
 
2266
        return rand.noncentral_f(dfn,dfd,nc,self._size)
 
2267
    def _pdf(self, x, dfn, dfd, nc):
 
2268
        n1,n2 = dfn, dfd
 
2269
        Px = exp(-nc/2+nc*n1*x/(2*(n2+n1*x)))
 
2270
        Px *= n1**(n1/2) * n2**(n2/2) * x**(n1/2-1)
 
2271
        Px *= (n2+n1*x)**(-(n1+n2)/2)
 
2272
        Px *= special.gamma(n1/2)*special.gamma(1+n2/2)
 
2273
        Px *= special.assoc_laguerre(-nc*n1*x/(2.0*(n2+n1*x)),n2/2,n1/2-1)
 
2274
        Px /= special.beta(n1/2,n2/2)*special.gamma((n1+n2)/2.0)
 
2275
    def _cdf(self, x, dfn, dfd, nc):
 
2276
        return special.ncfdtr(dfn,dfd,nc,x)
 
2277
    def _ppf(self, q, dfn, dfd, nc):
 
2278
        return special.ncfdtri(dfn, dfd, nc, q)
 
2279
    def _munp(self, n, dfn, dfd, nc):
 
2280
        val = (dfn *1.0/dfd)**n
 
2281
        val *= gam(n+0.5*dfn)*gam(0.5*dfd-n) / gam(dfd*0.5)
 
2282
        val *= exp(-nc / 2.0)
 
2283
        val *= special.hyp1f1(n+0.5*dfn, 0.5*dfn, 0.5*nc)
 
2284
        return val
 
2285
    def _stats(self, dfn, dfd, nc):        
 
2286
        mu = where(dfd <= 2, inf, dfd / (dfd-2.0)*(1+nc*1.0/dfn))
 
2287
        mu2 = where(dfd <=4, inf, 2*(dfd*1.0/dfn)**2.0 * \
 
2288
                    ((dfn+nc/2.0)**2.0 + (dfn+nc)*(dfd-2.0)) / \
 
2289
                    ((dfd-2.0)**2.0 * (dfd-4.0)))
 
2290
        return mu, mu2, None, None
 
2291
ncf = ncf_gen(a=0.0, name='ncf', longname="A non-central F distribution",
 
2292
              shapes="dfn,dfd,nc", extradoc="""
 
2293
 
 
2294
Non-central F distribution
 
2295
"""
 
2296
              )
 
2297
 
 
2298
## Student t distribution
 
2299
 
 
2300
class t_gen(rv_continuous):
 
2301
    def _rvs(self, df):
 
2302
        Y = f.rvs(df, df, size=self._size)
 
2303
        sY = sqrt(Y)
 
2304
        return 0.5*sqrt(df)*(sY-1.0/sY)
 
2305
    def _pdf(self, x, df):
 
2306
        r = arr(df*1.0)
 
2307
        Px = exp(special.gammaln((r+1)/2)-special.gammaln(r/2))
 
2308
        Px /= sqrt(r*pi)*(1+(x**2)/r)**((r+1)/2)
 
2309
        return Px
 
2310
    def _cdf(self, x, df):
 
2311
        return special.stdtr(df, x)
 
2312
    def _ppf(self, q, df):
 
2313
        return special.stdtrit(df, q)
 
2314
    def _stats(self, df):
 
2315
        mu2 = where(df > 2, df / (df-2.0), inf)
 
2316
        g1 = where(df > 3, 0.0, nan)
 
2317
        g2 = where(df > 4, 6.0/(df-4.0), nan)
 
2318
        return 0, mu2, g1, g2
 
2319
t = t_gen(name='t',longname="Student's T",
 
2320
          shapes="df", extradoc="""
 
2321
 
 
2322
Student's T distribution
 
2323
"""
 
2324
          )
 
2325
 
 
2326
## Non-central T distribution
 
2327
 
 
2328
class nct_gen(rv_continuous):
 
2329
    def _rvs(self, df, nc):
 
2330
        return norm.rvs(loc=nc,size=self._size)*sqrt(df) / sqrt(chi2.rvs(df,size=self._size))
 
2331
    def _pdf(self, x, df, nc):
 
2332
        n = df*1.0
 
2333
        nc = nc*1.0
 
2334
        x2 = x*x
 
2335
        ncx2 = nc*nc*x2
 
2336
        fac1 = n + x2
 
2337
        Px = n**(n/2) * special.gamma(n+1)
 
2338
        Px /= arr(2.0**n*exp(nc*nc/2)*fac1**(n/2)*special.gamma(n/2))
 
2339
        valF = ncx2 / (2*fac1)
 
2340
        trm1 = sqrt(2)*nc*x*special.hyp1f1(n/2+1,1.5,valF)
 
2341
        trm1 /= arr(fac1*special.gamma((n+1)/2))
 
2342
        trm2 = special.hyp1f1((n+1)/2,0.5,valF)
 
2343
        trm2 /= arr(sqrt(fac1)*special.gamma(n/2+1))
 
2344
        Px *= trm1+trm2
 
2345
        return Px
 
2346
    def _cdf(self, x, df, nc):
 
2347
        return special.nctdtr(df, nc, x)
 
2348
    def _ppf(self, q, df, nc):
 
2349
        return special.nctdtrit(df, nc, q)
 
2350
    def _stats(self, df, nc, moments='mv'):
 
2351
        mu, mu2, g1, g2 = None, None, None, None
 
2352
        val1 = gam((df-1.0)/2.0)
 
2353
        val2 = gam(df/2.0)
 
2354
        if 'm' in moments:
 
2355
            mu = nc*sqrt(df/2.0)*val1/val2
 
2356
        if 'v' in moments:
 
2357
            var = (nc*nc+1.0)*df/(df-2.0)
 
2358
            var -= nc*nc*df* val1**2 / 2.0 / val2**2
 
2359
            mu2 = var
 
2360
        if 's' in moments:
 
2361
            g1n = 2*nc*sqrt(df)*val1*((nc*nc*(2*df-7)-3)*val2**2 \
 
2362
                                      -nc*nc*(df-2)*(df-3)*val1**2)
 
2363
            g1d = (df-3)*sqrt(2*df*(nc*nc+1)/(df-2) - \
 
2364
                              nc*nc*df*(val1/val2)**2) * val2 * \
 
2365
                              (nc*nc*(df-2)*val1**2 - \
 
2366
                               2*(nc*nc+1)*val2**2)
 
2367
            g1 = g1n/g1d
 
2368
        if 'k' in moments:            
 
2369
            g2n = 2*(-3*nc**4*(df-2)**2 *(df-3) *(df-4)*val1**4 + \
 
2370
                     2**(6-2*df) * nc*nc*(df-2)*(df-4)* \
 
2371
                     (nc*nc*(2*df-7)-3)*pi* gam(df+1)**2 - \
 
2372
                     4*(nc**4*(df-5)-6*nc*nc-3)*(df-3)*val2**4)
 
2373
            g2d = (df-3)*(df-4)*(nc*nc*(df-2)*val1**2 - \
 
2374
                                 2*(nc*nc+1)*val2)**2
 
2375
            g2 = g2n / g2d
 
2376
        return mu, mu2, g1, g2
 
2377
nct = nct_gen(name="nct", longname="A Noncentral T",
 
2378
              shapes="df,nc", extradoc="""
 
2379
 
 
2380
Non-central Student T distribution
 
2381
"""
 
2382
              )
 
2383
 
 
2384
# Pareto
 
2385
 
 
2386
class pareto_gen(rv_continuous):
 
2387
    def _pdf(self, x, b):
 
2388
        return b * x**(-b-1)
 
2389
    def _cdf(self, x, b):
 
2390
        return 1 -  x**(-b)
 
2391
    def _ppf(self, q, b):
 
2392
        return pow(1-q, -1.0/b)
 
2393
    def _stats(self, b, moments='mv'):
 
2394
        mu, mu2, g1, g2 = None, None, None, None
 
2395
        if 'm' in moments:
 
2396
            mask = b > 1
 
2397
            bt = extract(mask,b)
 
2398
            mu = valarray(shape(b),value=inf)
 
2399
            insert(mu, mask, bt / (bt-1.0))
 
2400
        if 'v' in moments:
 
2401
            mask = b > 2
 
2402
            bt = extract( mask,b)
 
2403
            mu2 = valarray(shape(b), value=inf)
 
2404
            insert(mu2, mask, bt / (bt-2.0) / (bt-1.0)**2)
 
2405
        if 's' in moments:
 
2406
            mask = b > 3
 
2407
            bt = extract( mask,b)
 
2408
            g1 = valarray(shape(b), value=nan)
 
2409
            vals = 2*(bt+1.0)*sqrt(b-2.0)/((b-3.0)*sqrt(b))
 
2410
            insert(g1, mask, vals)
 
2411
        if 'k' in moments:
 
2412
            mask = b > 4
 
2413
            bt = extract( mask,b)
 
2414
            g2 = valarray(shape(b), value=nan)
 
2415
            vals = 6.0*polyval([1.0,1.0,-6,-2],bt)/ \
 
2416
                   polyval([1.0,-7.0,12.0,0.0],bt)
 
2417
            insert(g2, mask, vals)
 
2418
        return mu, mu2, g1, g2
 
2419
    def _entropy(self, c):
 
2420
        return 1 + 1.0/c - log(c)
 
2421
pareto = pareto_gen(a=1.0, name="pareto", longname="A Pareto",
 
2422
                    shapes="b", extradoc="""
 
2423
 
 
2424
Pareto distribution
 
2425
"""
 
2426
                    )
 
2427
 
 
2428
# LOMAX (Pareto of the second kind.)
 
2429
#  Special case of Pareto of the first kind (location=-1.0)
 
2430
 
 
2431
class lomax_gen(rv_continuous):
 
2432
    def _pdf(self, x, c):
 
2433
        return c*1.0/(1.0+x)**(c+1.0)
 
2434
    def _cdf(self, x, c):
 
2435
        return 1.0-1.0/(1.0+x)**c
 
2436
    def _ppf(self, q, c):
 
2437
        return pow(1.0-q,-1.0/c)-1
 
2438
    def _stats(self, c):
 
2439
        mu, mu2, g1, g2 = pareto.stats(c, loc=-1.0, moments='mvsk')
 
2440
        return mu, mu2, g1, g2
 
2441
    def _entropy(self, c):
 
2442
        return 1+1.0/c-log(c)
 
2443
lomax = lomax_gen(a=0.0, name="lomax",
 
2444
                  longname="A Lomax (Pareto of the second kind)",
 
2445
                  shapes="c", extradoc="""
 
2446
 
 
2447
Lomax (Pareto of the second kind) distribution
 
2448
"""
 
2449
                  )
 
2450
## Power-function distribution
 
2451
##   Special case of beta dist. with d =1.0
 
2452
 
 
2453
class powerlaw_gen(rv_continuous):
 
2454
    def _pdf(self, x, a):
 
2455
        return a*x**(a-1.0)
 
2456
    def _cdf(self, x, a):
 
2457
        return x**(a*1.0)
 
2458
    def _ppf(self, q, a):
 
2459
        return pow(q, 1.0/a)
 
2460
    def _stats(self, a):
 
2461
        return a/(a+1.0), a*(a+2.0)/(a+1.0)**2, \
 
2462
               2*(1.0-a)*sqrt((a+2.0)/(a*(a+3.0))), \
 
2463
               6*polyval([1,-1,-6,2],a)/(a*(a+3.0)*(a+4))
 
2464
    def _entropy(self, a):
 
2465
        return 1 - 1.0/a - log(a)
 
2466
powerlaw = powerlaw_gen(a=0.0, b=1.0, name="powerlaw",
 
2467
                        longname="A power-function",
 
2468
                        shapes="a", extradoc="""
 
2469
 
 
2470
Power-function distribution
 
2471
"""
 
2472
                        )
 
2473
 
 
2474
# Power log normal
 
2475
 
 
2476
class powerlognorm_gen(rv_continuous):
 
2477
    def _pdf(self, x, c, s):
 
2478
        return c/(x*s)*norm.pdf(log(x)/s)
 
2479
    def _cdf(self, x, c, s):
 
2480
        return 1.0 - pow(norm.cdf(-log(x)/s),c*1.0)
 
2481
    def _ppf(self, q, c, s):
 
2482
        return exp(-s*norm.ppf(pow(1.0-q,1.0/c)))
 
2483
powerlognorm = powerlognorm_gen(a=0.0, name="powerlognorm",
 
2484
                                longname="A power log-normal",
 
2485
                                shapes="c,s", extradoc="""
 
2486
 
 
2487
Power log-normal distribution
 
2488
"""
 
2489
                                )
 
2490
 
 
2491
# Power Normal
 
2492
 
 
2493
class powernorm_gen(norm_gen):
 
2494
    def _pdf(self, x, c):
 
2495
        return c*norm_gen._pdf(self, x)* \
 
2496
               (norm_gen._cdf(self, -x)**(c-1.0))
 
2497
    def _cdf(self, x, c):
 
2498
        return 1.0-norm_gen._cdf(self, -x)**(c*1.0)
 
2499
    def _ppf(self, q, c):
 
2500
        return -norm_gen._ppf(self, pow(1.0-q,1.0/c))
 
2501
powernorm = powernorm_gen(name='powernorm', longname="A power normal",
 
2502
                          shapes="c", extradoc="""
 
2503
 
 
2504
Power normal distribution
 
2505
"""
 
2506
                          )
 
2507
 
 
2508
# R-distribution ( a general-purpose distribution with a
 
2509
#  variety of shapes.
 
2510
 
 
2511
class rdist_gen(rv_continuous):
 
2512
    def _pdf(self, x, c):
 
2513
        return pow((1.0-x*x),c/2.0-1) / special.beta(0.5,c/2.0)
 
2514
    def _cdf(self, x, c):
 
2515
        return 0.5 + x/special.beta(0.5,c/2.0)* \
 
2516
               special.hyp2f1(0.5,1.0-c/2.0,1.5,x*x)
 
2517
    def _munp(self, c):
 
2518
        return (1-(n % 2))*special.beta((n+1.0)/2,c/2.0)
 
2519
rdist = rdist_gen(a=-1.0,b=1.0, name="rdist", longname="An R-distributed",
 
2520
                  shapes="c", extradoc="""
 
2521
 
 
2522
R-distribution
 
2523
"""
 
2524
                  )
 
2525
 
 
2526
# Rayleigh distribution (this is chi with df=2 and loc=0.0)
 
2527
# scale is the mode.
 
2528
 
 
2529
class rayleigh_gen(rv_continuous):
 
2530
    def _rvs(self):
 
2531
        return chi.rvs(2,size=self._size)
 
2532
    def _pdf(self, r):
 
2533
        return r*exp(-r*r/2.0)
 
2534
    def _cdf(self, r):
 
2535
        return 1.0-exp(-r*r/2.0)
 
2536
    def _ppf(self, q):
 
2537
        return sqrt(-2*log(1-q))
 
2538
    def _stats(self):
 
2539
        val = 4-pi
 
2540
        return pi/2, val/2, 2*(pi-3)*sqrt(pi)/val**1.5, \
 
2541
               6*pi/val-16/val**2
 
2542
    def _entropy(self):
 
2543
        return _EULER/2.0 + 1 - 0.5*log(2)
 
2544
rayleigh = rayleigh_gen(a=0.0, name="rayleigh",
 
2545
                        longname="A Rayleigh",
 
2546
                        extradoc="""
 
2547
 
 
2548
Rayleigh distribution
 
2549
"""
 
2550
                        )
 
2551
 
 
2552
# Reciprocal Distribution
 
2553
class reciprocal_gen(rv_continuous):
 
2554
    def _argcheck(self, a, b):
 
2555
        self.a = a
 
2556
        self.b = b
 
2557
        self.d = log(b*1.0 / a)
 
2558
        return (a > 0) & (b > 0) & (b > a)
 
2559
    def _pdf(self, x, a, b):
 
2560
        # argcheck should be called before _pdf
 
2561
        return 1.0/(x*self.d)
 
2562
    def _cdf(self, x, a, b):
 
2563
        return (log(x)-log(a)) / self.d
 
2564
    def _ppf(self, q, a, b):
 
2565
        return a*pow(b*1.0/a,q)
 
2566
    def _munp(self, n, a, b):
 
2567
        return 1.0/self.d / n * (pow(b*1.0,n) - pow(a*1.0,n))
 
2568
    def _entropy(self,a,b):
 
2569
        return 0.5*log(a*b)+log(log(b/a))
 
2570
reciprocal = reciprocal_gen(name="reciprocal",
 
2571
                            longname="A reciprocal",
 
2572
                            shapes="a,b", extradoc="""
 
2573
 
 
2574
Reciprocal distribution
 
2575
"""
 
2576
                            )
 
2577
 
 
2578
# Rice distribution
 
2579
 
 
2580
class rice_gen(rv_continuous):
 
2581
    def _pdf(self, x, b):
 
2582
        return x*exp(-(x*x+b*b)/2.0)*special.i0(x*b)
 
2583
    def _munp(self, n, b):
 
2584
        nd2 = n/2.0
 
2585
        n1 = 1+nd2
 
2586
        b2 = b*b/2.0
 
2587
        return 2.0**(nd2)*exp(-b2)*special.gamma(n1) * \
 
2588
               special.hyp1f1(n1,1,b2)
 
2589
rice = rice_gen(a=0.0, name="rice", longname="A Rice",
 
2590
                shapes="b", extradoc="""
 
2591
 
 
2592
Rician distribution
 
2593
"""
 
2594
                )
 
2595
 
 
2596
# Reciprocal Inverse Gaussian
 
2597
 
 
2598
class recipinvgauss_gen(rv_continuous):
 
2599
    def _pdf(self, x, mu):
 
2600
        return 1.0/sqrt(2*pi*x)*exp(-(1-mu*x)**2.0 / (2*x*mu**2.0))
 
2601
    def _cdf(self, x, mu):
 
2602
        trm1 = 1.0/mu - x
 
2603
        trm2 = 1.0/mu + x
 
2604
        isqx = 1.0/sqrt(x)
 
2605
        return 1.0-norm.cdf(isqx*trm1)-exp(2.0/mu)*norm.cdf(-isqx*trm2)
 
2606
recipinvgauss = recipinvgauss_gen(a=0.0, name='recipinvgauss',
 
2607
                                  longname="A reciprocal inverse Gaussian",
 
2608
                                  shapes="mu", extradoc="""
 
2609
 
 
2610
Reciprocal inverse Gaussian
 
2611
"""
 
2612
                                  )
 
2613
 
 
2614
# Semicircular
 
2615
 
 
2616
class semicircular_gen(rv_continuous):
 
2617
    def _pdf(self, x):
 
2618
        return 2.0/pi*sqrt(1-x*x)
 
2619
    def _cdf(self, x):
 
2620
        return 0.5+1.0/pi*(x*sqrt(1-x*x) + arcsin(x))
 
2621
    def _stats(self):
 
2622
        return 0, 0.25, 0, -1.0
 
2623
    def _entropy(self):
 
2624
        return 0.64472988584940017414        
 
2625
semicircular = semicircular_gen(a=-1.0,b=1.0, name="semicircular",
 
2626
                                longname="A semicircular",
 
2627
                                extradoc="""
 
2628
 
 
2629
Semicircular distribution
 
2630
"""
 
2631
                                )
 
2632
 
 
2633
# Triangular
 
2634
# up-sloping line from loc to (loc + c*scale) and then downsloping line from
 
2635
#    loc + c*scale to loc + scale
 
2636
 
 
2637
# _trstr = "Left must be <= mode which must be <= right with left < right"
 
2638
class triang_gen(rv_continuous):
 
2639
    def _argcheck(self, c):
 
2640
        return (c >= 0) & (c <= 1)
 
2641
    def _pdf(self, x, c):
 
2642
        return where(x < c, 2*x/c, 2*(1-x)/(1-c))
 
2643
    def _cdf(self, x, c):
 
2644
        return where(x < c, x*x/c, (x*x-2*x+c)/(c-1))
 
2645
    def _ppf(self, q, c):
 
2646
        return where(q < c, sqrt(c*q), 1-sqrt((1-c)*(1-q)))
 
2647
    def _stats(self, c):
 
2648
        return (c+1.0)/3.0, (1.0-c+c*c)/18, sqrt(2)*(2*c-1)*(c+1)*(c-2) / \
 
2649
               (5*(1.0-c+c*c)**1.5), -3.0/5.0
 
2650
    def _entropy(self,c):
 
2651
        return 0.5-log(2)
 
2652
triang = triang_gen(a=0.0, b=1.0, name="triang", longname="A Triangular",
 
2653
                    shapes="c", extradoc="""
 
2654
 
 
2655
Triangular distribution
 
2656
 
 
2657
    up-sloping line from loc to (loc + c*scale) and then downsloping
 
2658
    for (loc + c*scale) to (loc+scale).
 
2659
 
 
2660
    - standard form is in the range [0,1] with c the mode.
 
2661
    - location parameter shifts the start to loc
 
2662
    - scale changes the width from 1 to scale
 
2663
"""
 
2664
                    )
 
2665
 
 
2666
# Truncated Exponential
 
2667
 
 
2668
class truncexpon_gen(rv_continuous):
 
2669
    def _argcheck(self, b):
 
2670
        self.b = b
 
2671
        return (b > 0)
 
2672
    def _pdf(self, x, b):
 
2673
        return exp(-x)/(1-exp(-b))
 
2674
    def _cdf(self, x, b):
 
2675
        return (1.0-exp(-x))/(1-exp(-b))
 
2676
    def _ppf(self, q, b):
 
2677
        return -log(1-q+q*exp(-b))
 
2678
    def _munp(self, n, b):
 
2679
        return gam(n+1)-special.gammainc(1+n,b)
 
2680
    def _entropy(self, b):
 
2681
        eB = exp(b)
 
2682
        return log(eB-1)+(1+eB*(b-1.0))/(1.0-eB)
 
2683
truncexpon = truncexpon_gen(a=0.0, name='truncexpon',
 
2684
                            longname="A truncated exponential",
 
2685
                            shapes="b", extradoc="""
 
2686
 
 
2687
Truncated exponential distribution
 
2688
"""
 
2689
                            )
 
2690
 
 
2691
# Truncated Normal
 
2692
 
 
2693
class truncnorm_gen(rv_continuous):
 
2694
    def _argcheck(self, a, b):
 
2695
        self.a = a
 
2696
        self.b = b
 
2697
        self.nb = norm._cdf(b)
 
2698
        self.na = norm._cdf(a)
 
2699
        return (a != b)
 
2700
    def _pdf(self, x, a, b):
 
2701
        return norm._pdf(x) / (self.nb - self.na)
 
2702
    def _cdf(self, x, a, b):
 
2703
        return (norm._cdf(x) - self.na) / (self.nb - self.na)
 
2704
    def _ppf(self, q, a, b):
 
2705
        return norm._ppf(q*self.nb + self.na*(1.0-q))
 
2706
    def _stats(self, a, b):
 
2707
        nA, nB = self.na, self.nb
 
2708
        d = nB - nA
 
2709
        pA, pB = norm._pdf(a), norm._pdf(b)
 
2710
        mu = (pB - pA) / d
 
2711
        mu2 = 1 + (a*pA - b*pB) / d - mu*mu
 
2712
        return mu, mu2, None, None
 
2713
truncnorm = truncnorm_gen(name='truncnorm', longname="A truncated normal",
 
2714
                          shapes="a,b", extradoc="""
 
2715
 
 
2716
Truncated Normal distribution.
 
2717
 
 
2718
  The standard form of this distribution is a standard normal truncated to the
 
2719
  range [a,b] --- notice that a and b are defined over the domain
 
2720
  of the standard normal.  To convert clip values for a specific mean and
 
2721
  standard deviation use a,b = (myclip_a-my_mean)/my_std, (myclip_b-my_mean)/my_std
 
2722
"""
 
2723
                          )
 
2724
 
 
2725
# Tukey-Lambda
 
2726
# A flexible distribution ranging from Cauchy (lam=-1)
 
2727
#   to logistic (lam=0.0)
 
2728
#   to approx Normal (lam=0.14)
 
2729
#   to u-shape (lam = 0.5)
 
2730
#   to Uniform from -1 to 1 (lam = 1)
 
2731
 
 
2732
class tukeylambda_gen(rv_continuous):
 
2733
    def _pdf(self, x, lam):
 
2734
        Fx = arr(special.tklmbda(x,lam))
 
2735
        Px = Fx**(lam-1.0) + (arr(1-Fx))**(lam-1.0)
 
2736
        Px = 1.0/arr(Px)
 
2737
        return where((lam > 0) & (abs(x) < 1.0/lam), Px, 0.0)
 
2738
    def _cdf(self, x, lam):
 
2739
        return special.tklmbda(x, lam)
 
2740
    def _ppf(self, q, lam):
 
2741
        q = q*1.0
 
2742
        vals1 = (q**lam - (1-q)**lam)/lam
 
2743
        vals2 = log(q/(1-q))
 
2744
        return where((lam == 0)&(q==q), vals2, vals1)
 
2745
    def _stats(self, lam):
 
2746
        mu2 = 2*gam(lam+1.5)-lam*pow(4,-lam)*sqrt(pi)*gam(lam)*(1-2*lam)
 
2747
        mu2 /= lam*lam*(1+2*lam)*gam(1+1.5)
 
2748
        mu4 = 3*gam(lam)*gam(lam+0.5)*pow(2,-2*lam) / lam**3 / gam(2*lam+1.5)
 
2749
        mu4 += 2.0/lam**4 / (1+4*lam)
 
2750
        mu4 -= 2*sqrt(3)*gam(lam)*pow(2,-6*lam)*pow(3,3*lam) * \
 
2751
               gam(lam+1.0/3)*gam(lam+2.0/3) / (lam**3.0 * gam(2*lam+1.5) * \
 
2752
                                                gam(lam+0.5))
 
2753
        g2 = mu4 / mu2 / mu2 - 3.0
 
2754
                                               
 
2755
        return 0, mu2, 0, g2
 
2756
    def _entropy(self, lam):
 
2757
        def integ(p):
 
2758
            return log(pow(p,lam-1)+pow(1-p,lam-1))
 
2759
        return scipy.integrate.quad(integ,0,1)[0]
 
2760
tukeylambda = tukeylambda_gen(name='tukeylambda', longname="A Tukey-Lambda",
 
2761
                              shapes="lam", extradoc="""
 
2762
 
 
2763
Tukey-Lambda distribution
 
2764
 
 
2765
   A flexible distribution ranging from Cauchy (lam=-1)
 
2766
   to logistic (lam=0.0)
 
2767
   to approx Normal (lam=0.14)
 
2768
   to u-shape (lam = 0.5)
 
2769
   to Uniform from -1 to 1 (lam = 1)
 
2770
"""
 
2771
                              )
 
2772
 
 
2773
# Uniform
 
2774
# loc to loc + scale
 
2775
 
 
2776
class uniform_gen(rv_continuous):
 
2777
    def _rvs(self):
 
2778
        return rand.uniform(0.0,1.0,self._size)
 
2779
    def _pdf(self, x):
 
2780
        return 1.0*(x==x)
 
2781
    def _cdf(self, x):
 
2782
        return x
 
2783
    def _ppf(self, q):
 
2784
        return q
 
2785
    def _stats(self):
 
2786
        return 0.5, 1.0/12, 0, -1.2
 
2787
    def _entropy(self):
 
2788
        return 0.0
 
2789
uniform = uniform_gen(a=0.0,b=1.0, name='uniform', longname="A uniform",
 
2790
                      extradoc="""
 
2791
 
 
2792
Uniform distribution
 
2793
 
 
2794
   constant between loc and loc+scale
 
2795
"""
 
2796
                      )
 
2797
 
 
2798
# Von-Mises
 
2799
 
 
2800
# if x is not in range or loc is not in range it assumes they are angles
 
2801
#   and converts them to [-pi, pi] equivalents.
 
2802
 
 
2803
eps = scipy_base.limits.double_epsilon
 
2804
 
 
2805
class vonmises_gen(rv_continuous):
 
2806
    def _rvs(self, b):
 
2807
        return rv._inst._von_Mises(b,size=(self._size,))
 
2808
    def _pdf(self, x, b):
 
2809
        x = arr(angle(exp(1j*x)))
 
2810
        Px = where(b < 100, exp(b*cos(x)) / (2*pi*special.i0(b)),
 
2811
                   norm.pdf(x, 0.0, sqrt(1.0/b)))
 
2812
        return Px
 
2813
    def _cdf(self, x, b):
 
2814
        x = arr(angle(exp(1j*x)))
 
2815
        eps2 = sqrt(eps)
 
2816
 
 
2817
        c_xsimple = atleast_1d((b==0)&(x==x))
 
2818
        c_xiter = atleast_1d((b<100)&(b > 0)&(x==x))
 
2819
        c_xnormal = atleast_1d((b>=100)&(x==x))
 
2820
        c_bad = atleast_1d((b<=0) | (x != x))
 
2821
    
 
2822
        indxiter = nonzero(c_xiter)
 
2823
        xiter = take(x, indxiter)
 
2824
 
 
2825
        vals = ones(len(c_xsimple),Num.Float)
 
2826
        putmask(vals, c_bad, nan)
 
2827
        putmask(vals, c_xsimple, x / 2.0/pi)
 
2828
        st = sqrt(b-0.5)
 
2829
        st = where(isnan(st),0.0,st)
 
2830
        putmask(vals, c_xnormal, norm.cdf(x, scale=st))
 
2831
        
 
2832
        biter = take(atleast_1d(b)*(x==x), indxiter)
 
2833
        if len(xiter) > 0:
 
2834
            fac = special.i0(biter)
 
2835
            x2 = xiter
 
2836
            val = x2 / 2.0/ pi
 
2837
            for j in range(1,501):
 
2838
                trm1 = special.iv(j,biter)/j/fac
 
2839
                trm2 = sin(j*x2)/pi
 
2840
                val += trm1*trm2
 
2841
                if all(trm1 < eps2):
 
2842
                    break
 
2843
            if (j == 500):
 
2844
                print "Warning: did not converge..."
 
2845
            put(vals, indxiter, val)        
 
2846
        return vals + 0.5
 
2847
    def _stats(self, b):
 
2848
        return 0, None, 0, None
 
2849
vonmises = vonmises_gen(name='vonmises', longname="A Von Mises",
 
2850
                        shapes="b", extradoc="""
 
2851
 
 
2852
Von Mises distribution
 
2853
 
 
2854
  if x is not in range or loc is not in range it assumes they are angles
 
2855
     and converts them to [-pi, pi] equivalents.
 
2856
 
 
2857
"""
 
2858
                        )
 
2859
 
 
2860
 
 
2861
## Wald distribution (Inverse Normal with shape parameter mu=1.0)
 
2862
 
 
2863
class wald_gen(invnorm_gen):
 
2864
    def _rvs(self):
 
2865
        return invnorm_gen._rvs(self, 1.0)
 
2866
    def _pdf(self, x):
 
2867
        return invnorm.pdf(x,1.0)
 
2868
    def _cdf(self, x):
 
2869
        return invnorm.cdf(x,1,0)
 
2870
    def _stats(self):
 
2871
        return 1.0, 1.0, 3.0, 15.0
 
2872
wald = wald_gen(a=0.0, name="wald", longname="A Wald",
 
2873
                extradoc="""
 
2874
 
 
2875
Wald distribution
 
2876
"""
 
2877
                )
 
2878
    
 
2879
## Weibull
 
2880
## See Frechet
 
2881
 
 
2882
# Wrapped Cauchy
 
2883
 
 
2884
class wrapcauchy_gen(rv_continuous):
 
2885
    def _argcheck(self, c):
 
2886
        return (c > 0) & (c < 1)
 
2887
    def _pdf(self, x, c):
 
2888
        return (1.0-c*c)/(2*pi*(1+c*c-2*c*cos(x)))
 
2889
    def _cdf(self, x, c):
 
2890
        output = 0.0*x
 
2891
        val = (1.0+c)/(1.0-c)
 
2892
        c1 = x<pi
 
2893
        c2 = 1-c1
 
2894
        xp = extract( c1,x)
 
2895
        valp = extract(c1,val)
 
2896
        xn = extract( c2,x)
 
2897
        valn = extract(c2,val)
 
2898
        if (any(xn)):
 
2899
            xn = 2*pi - xn
 
2900
            yn = tan(xn/2.0)
 
2901
            on = 1.0-1.0/pi*arctan(valn*yn)
 
2902
            insert(output, c2, on)
 
2903
        if (any(xp)):
 
2904
            yp = tan(xp/2.0)
 
2905
            op = 1.0/pi*arctan(valp*yp)
 
2906
            insert(output, c1, op)
 
2907
        return output
 
2908
    def _ppf(self, q, c):
 
2909
        val = (1.0-c)/(1.0+c)
 
2910
        rcq = 2*arctan(val*tan(pi*q))
 
2911
        rcmq = 2*pi-2*arctan(val*tan(pi*(1-q)))
 
2912
        return where(q < 1.0/2, rcq, rcmq)
 
2913
    def _entropy(self, c):
 
2914
        return log(2*pi*(1-c*c))
 
2915
wrapcauchy = wrapcauchy_gen(a=0.0,b=2*pi, name='wrapcauchy',
 
2916
                            longname="A wrapped Cauchy",
 
2917
                            shapes="c", extradoc="""
 
2918
 
 
2919
Wrapped Cauchy distribution
 
2920
"""
 
2921
                            )
 
2922
 
 
2923
### DISCRETE DISTRIBUTIONS
 
2924
###
 
2925
 
 
2926
def entropy(pk,qk=None):
 
2927
    """S = entropy(pk,qk=None)
 
2928
 
 
2929
    calculate the entropy of a distribution given the p_k values
 
2930
    S = -sum(pk * log(pk))
 
2931
 
 
2932
    If qk is not None, then compute a relative entropy
 
2933
    S = -sum(pk * log(pk / qk))
 
2934
 
 
2935
    Routine will normalize pk and qk if they don't sum to 1
 
2936
    """
 
2937
    pk = arr(pk)
 
2938
    pk = 1.0* pk / sum(pk)
 
2939
    if qk is None:
 
2940
        vec = where(pk == 0, 0.0, pk*log(pk))
 
2941
    else:
 
2942
        qk = arr(qk)
 
2943
        if len(qk) != len(pk):
 
2944
            raise ValueError, "qk and pk must have same length."
 
2945
        qk = 1.0*qk / sum(qk)
 
2946
        # If qk is zero anywhere, then unless pk is zero at those places
 
2947
        #   too, the relative entropy is infinite.
 
2948
        if any(take(pk,nonzero(qk==0.0))!=0.0):
 
2949
            return inf
 
2950
        vec = where (pk == 0, 0.0, pk*log(pk / qk))
 
2951
    return -sum(vec)
 
2952
    
 
2953
 
 
2954
## Handlers for generic case where xk and pk are given
 
2955
 
 
2956
def _drv_pdf(self, xk, *args):
 
2957
    try:
 
2958
        return self.P[xk]
 
2959
    except KeyError:
 
2960
        return 0.0
 
2961
 
 
2962
def _drv_cdf(self, xk, *args):
 
2963
    indx = argmax((self.xk>xk))-1
 
2964
    return self.F[self.xk[indx]]
 
2965
 
 
2966
def _drv_ppf(self, q, *args):
 
2967
    indx = argmax((self.qvals>=q)) 
 
2968
    return self.Finv[self.qvals[indx]]
 
2969
 
 
2970
def _drv_nonzero(self, k, *args):
 
2971
    return 1
 
2972
 
 
2973
def _drv_moment(self, n, *args):
 
2974
    n = arr(n)
 
2975
    return sum(self.xk**n[NewAxis,...] * self.pk, axis=0)
 
2976
 
 
2977
def _drv_moment_gen(self, t, *args):
 
2978
    t = arr(t)
 
2979
    return sum(exp(self.xk * t[NewAxis,...]) * self.pk, axis=0)
 
2980
 
 
2981
def _drv2_moment(self, n, *args):
 
2982
    tot = 0.0
 
2983
    diff = 1e100
 
2984
    pos = self.a
 
2985
    count = 0
 
2986
    while (pos <= self.b) and ((pos >= (self.b + self.a)/2.0) and \
 
2987
                               (diff > self.moment_tol)):
 
2988
        diff = pos**n * self._pdf(pos,*args)
 
2989
        tot += diff
 
2990
        pos += self.inc
 
2991
 
 
2992
def _drv2_ppfsingle(self, q, *args):  # Use basic bisection algorithm
 
2993
    b = self.invcdf_b
 
2994
    a = self.invcdf_a
 
2995
    if isinf(b):            # Be sure ending point is > q
 
2996
        b = max(100*q,10)
 
2997
        while 1:
 
2998
            if b >= self.b: qb = 1.0; break
 
2999
            qb = self._cdf(b,*args)
 
3000
            if (qb < q): b += 10
 
3001
            else: break
 
3002
    else:
 
3003
        qb = 1.0
 
3004
    if isinf(a):    # be sure starting point < q
 
3005
        a = min(-100*q,-10)
 
3006
        while 1:
 
3007
            if a <= self.a: qb = 0.0; break
 
3008
            qa = self._cdf(a,*args)
 
3009
            if (qa > q): a -= 10
 
3010
            else: break
 
3011
    else:
 
3012
        qa = self._cdf(a, *args)
 
3013
        
 
3014
    while 1:
 
3015
        if (qa == q):
 
3016
            return a
 
3017
        if (qb == q):
 
3018
            return b
 
3019
        if b == a+1:
 
3020
            return b
 
3021
        c = int((a+b)/2.0)
 
3022
        qc = self._cdf(c, *args)            
 
3023
        if (qc < q):
 
3024
            a = c
 
3025
            qa = qc
 
3026
        elif (qc > q):
 
3027
            b = c
 
3028
            qb = qc
 
3029
        else:
 
3030
            return c                
 
3031
 
 
3032
def reverse_dict(dict):
 
3033
    newdict = {}
 
3034
    for key in dict.keys():
 
3035
        newdict[dict[key]] = key
 
3036
    return newdict
 
3037
 
 
3038
def make_dict(keys, values):
 
3039
    d = {}
 
3040
    for key, value in zip(keys, values):
 
3041
        d[key] = value
 
3042
    return d
 
3043
 
 
3044
# Must over-ride one of _pmf or _cdf or pass in
 
3045
#  x_k, p(x_k) lists in initialization
 
3046
 
 
3047
class rv_discrete:
 
3048
    """A generic discrete random variable.
 
3049
 
 
3050
    Discrete random variables are defined from a standard form.
 
3051
    The standard form may require some other parameters to complete
 
3052
    its specification.  The distribution methods also take an optional location
 
3053
    parameter using loc= keyword.  The default is loc=0.  The calling form
 
3054
    of the methods follow:
 
3055
 
 
3056
    generic.rvs(<shape(s)>,loc=0)
 
3057
        - random variates 
 
3058
 
 
3059
    generic.pmf(x,<shape(s)>,loc=0)
 
3060
        - probability mass function
 
3061
 
 
3062
    generic.cdf(x,<shape(s)>,loc=0)
 
3063
        - cumulative density function
 
3064
 
 
3065
    generic.sf(x,<shape(s)>,loc=0)
 
3066
        - survival function (1-cdf --- sometimes more accurate)
 
3067
 
 
3068
    generic.ppf(q,<shape(s)>,loc=0)
 
3069
        - percent point function (inverse of cdf --- percentiles)
 
3070
 
 
3071
    generic.isf(q,<shape(s)>,loc=0)
 
3072
        - inverse survival function (inverse of sf)
 
3073
 
 
3074
    generic.stats(<shape(s)>,loc=0,moments='mv')
 
3075
        - mean('m'), variance('v'), skew('s'), and/or kurtosis('k')
 
3076
 
 
3077
    generic.entropy(<shape(s)>,loc=0)
 
3078
        - entropy of the RV
 
3079
 
 
3080
    Alternatively, the object may be called (as a function) to fix
 
3081
       the shape and location parameters returning a
 
3082
       "frozen" discrete RV object:
 
3083
 
 
3084
    myrv = generic(<shape(s)>,loc=0)
 
3085
        - frozen RV object with the same methods but holding the
 
3086
            given shape and location fixed.
 
3087
 
 
3088
    You can construct an aribtrary discrete rv where P{X=xk} = pk
 
3089
    by passing to the rv_discrete initialization method (through the values=
 
3090
    keyword) a tuple of sequences (xk,pk) which describes only those values of
 
3091
    X (xk) that occur with nonzero probability (pk).  
 
3092
    """
 
3093
    def __init__(self, a=0, b=inf, name=None, badvalue=None,
 
3094
                 moment_tol=1e-8,values=None,inc=1,longname=None,
 
3095
                 shapes=None, extradoc=None):
 
3096
        if badvalue is None:
 
3097
            badvalue = nan
 
3098
        self.badvalue = badvalue
 
3099
        self.a = a
 
3100
        self.b = b
 
3101
        self.invcdf_a = a
 
3102
        self.invcdf_b = b
 
3103
        self.name = name
 
3104
        self.moment_tol = moment_tol
 
3105
        self.inc = inc
 
3106
        self._cdfvec = sgf(self._cdfsingle,otypes='d')
 
3107
        self.return_integers = 1
 
3108
        self.vecentropy = vectorize(self._entropy)
 
3109
 
 
3110
        if values is not None:
 
3111
            self.xk, self.pk = values
 
3112
            self.return_integers = 0
 
3113
            indx = argsort(ravel(self.xk))
 
3114
            self.xk = take(ravel(self.xk),indx)
 
3115
            self.pk = take(ravel(self.pk),indx)
 
3116
            self.a = self.xk[0]
 
3117
            self.b = self.xk[-1]
 
3118
            self.P = make_dict(self.xk, self.pk)
 
3119
            self.qvals = scipy_base.cumsum(self.pk)
 
3120
            self.F = make_dict(self.xk, self.qvals)
 
3121
            self.Finv = reverse_dict(self.F)
 
3122
            self._ppf = new.instancemethod(sgf(_drv_ppf,otypes='d'),
 
3123
                                           self, rv_discrete)
 
3124
            self._pmf = new.instancemethod(sgf(_drv_pmf,otypes='d'),
 
3125
                                           self, rv_discrete)
 
3126
            self._cdf = new.instancemethod(sgf(_drv_cdf,otypes='d'),
 
3127
                                           self, rv_discrete)
 
3128
            self._nonzero = new.instancemethod(_drv_nonzero, self, rv_discrete)
 
3129
            self.generic_moment = new.instancemethod(_drv_moment,
 
3130
                                                     self, rv_discrete)
 
3131
            self.moment_gen = new.instancemethod(_drv_moment_gen,
 
3132
                                                 self, rv_discrete)
 
3133
            self.numargs=0
 
3134
        else:
 
3135
            self._vecppf = new.instancemethod(sgf(_drv2_ppfsingle,otypes='d'),
 
3136
                                              self, rv_discrete)
 
3137
            self.generic_moment = new.instancemethod(sgf(_drv2_moment,
 
3138
                                                         otypes='d'),
 
3139
                                                     self, rv_discrete)
 
3140
            cdf_signature = inspect.getargspec(self._cdf.im_func)
 
3141
            numargs1 = len(cdf_signature[0]) - 2
 
3142
            pmf_signature = inspect.getargspec(self._pmf.im_func)
 
3143
            numargs2 = len(pmf_signature[0]) - 2
 
3144
            self.numargs = max(numargs1, numargs2)
 
3145
 
 
3146
        if longname is None:
 
3147
            if name[0] in ['aeiouAEIOU']: hstr = "An "
 
3148
            else: hstr = "A "
 
3149
            longname = hstr + name
 
3150
        if self.__doc__ is None:
 
3151
            self.__doc__ = rv_discrete.__doc__
 
3152
        if self.__doc__ is not None:
 
3153
            self.__doc__ = self.__doc__.replace("A Generic",longname)
 
3154
            if name is not None:
 
3155
                self.__doc__ = self.__doc__.replace("generic",name)
 
3156
            if shapes is None:
 
3157
                self.__doc__ = self.__doc__.replace("<shape(s)>,","")
 
3158
            else:
 
3159
                self.__doc__ = self.__doc__.replace("<shape(s)>",shapes)
 
3160
            ind = self.__doc__.find("You can construct an arbitrary")
 
3161
            self.__doc__ = self.__doc__[:ind].strip()
 
3162
            if extradoc is not None:
 
3163
                self.__doc__ = self.__doc__ + extradoc
 
3164
 
 
3165
    def _rvs(self, *args):
 
3166
        return self._ppf(rand.sample(self._size),*args)
 
3167
 
 
3168
    def __fix_loc(self, args, loc):
 
3169
        N = len(args)
 
3170
        if N > self.numargs:
 
3171
            if N == self.numargs + 1 and loc is None:  # loc is given without keyword
 
3172
                loc = args[-1]
 
3173
            args = args[:self.numargs]
 
3174
        if loc is None:
 
3175
            loc = 0
 
3176
        return args, loc
 
3177
 
 
3178
    def _nonzero(self, k, *args):
 
3179
        return floor(k)==k
 
3180
    
 
3181
    def _argcheck(self, *args):
 
3182
        cond = 1
 
3183
        for arg in args:
 
3184
            cond &= (arg > 0)
 
3185
        return cond
 
3186
 
 
3187
    def _pmf(self, k, *args):
 
3188
        return self.cdf(k,*args) - self.cdf(k-1,*args)
 
3189
 
 
3190
    def _cdfsingle(self, k, *args):
 
3191
        m = arange(int(self.a),k+1)
 
3192
        return sum(self._pmf(m,*args))
 
3193
 
 
3194
    def _cdf(self, x, *args):
 
3195
        k = floor(x)
 
3196
        return self._cdfvec(k,*args)
 
3197
    
 
3198
    def _sf(self, x, *args):
 
3199
        return 1.0-self._cdf(x,*args)
 
3200
        
 
3201
    def _ppf(self, q, *args):
 
3202
        return self._vecppf(q, *args)
 
3203
 
 
3204
    def _isf(self, q, *args):
 
3205
        return self._ppf(1-q,*args)
 
3206
 
 
3207
    def _stats(self, *args):
 
3208
        return None, None, None, None
 
3209
 
 
3210
    def _munp(self, n, *args):
 
3211
        return self.generic_moment(n)
 
3212
 
 
3213
 
 
3214
    def rvs(self, *args, **kwds):
 
3215
        loc,size=map(kwds.get,['loc','size'])
 
3216
        args, loc = self.__fix_loc(args, loc)
 
3217
        cond = self._argcheck(*args)
 
3218
        if not all(cond):
 
3219
            raise ValueError, "Domain error in arguments."
 
3220
 
 
3221
        if size is None:
 
3222
            size = 1
 
3223
        else:
 
3224
            self._size = product(size)
 
3225
        if scipy.isscalar(size):
 
3226
            self._size = size
 
3227
            size = (size,)
 
3228
            
 
3229
        vals = reshape(self._rvs(*args),size)
 
3230
        if self.return_integers:
 
3231
            vals = arr(vals)
 
3232
            if vals.typecode() not in scipy.typecodes['AllInteger']:
 
3233
                vals = vals.astype(Num.Int)
 
3234
        return vals + loc
 
3235
 
 
3236
    def pmf(self, k,*args, **kwds):
 
3237
        """Probability mass function at k of the given RV.
 
3238
 
 
3239
        *args
 
3240
        =====
 
3241
        The shape parameter(s) for the distribution (see docstring of the
 
3242
           instance object for more information)
 
3243
        
 
3244
        **kwds
 
3245
        ======
 
3246
        loc   - location parameter (default=0)
 
3247
        """
 
3248
        loc = kwds.get('loc')
 
3249
        args, loc  = self.__fix_loc(args, loc)
 
3250
        k,loc = map(arr,(k,loc))
 
3251
        args = tuple(map(arr,args))
 
3252
        k = arr((k-loc))
 
3253
        cond0 = self._argcheck(*args)
 
3254
        cond1 = (k >= self.a) & (k <= self.b) & self._nonzero(k,*args)
 
3255
        cond = cond0 & cond1
 
3256
        output = zeros(shape(cond),'d')
 
3257
        insert(output,(1-cond0)*(cond1==cond1),self.badvalue)
 
3258
        goodargs = argsreduce(cond, *((k,)+args))
 
3259
        insert(output,cond,self._pmf(*goodargs))
 
3260
        return output
 
3261
        
 
3262
    def cdf(self, k, *args, **kwds):
 
3263
        """Cumulative distribution function at k of the given RV
 
3264
 
 
3265
        *args
 
3266
        =====
 
3267
        The shape parameter(s) for the distribution (see docstring of the
 
3268
           instance object for more information)
 
3269
        
 
3270
        **kwds
 
3271
        ======
 
3272
        loc   - location parameter (default=0)
 
3273
        """        
 
3274
        loc = kwds.get('loc')
 
3275
        args, loc = self.__fix_loc(args, loc)
 
3276
        k,loc = map(arr,(k,loc))
 
3277
        args = tuple(map(arr,args))
 
3278
        k = arr((k-loc))
 
3279
        cond0 = self._argcheck(*args)
 
3280
        cond1 = (k >= self.a) & (k < self.b)
 
3281
        cond2 = (k >= self.b)
 
3282
        cond = cond0 & cond1
 
3283
        output = zeros(shape(cond),'d')
 
3284
        insert(output,(1-cond0)*(cond1==cond1),self.badvalue)
 
3285
        insert(output,cond2*(cond0==cond0), 1.0)
 
3286
        goodargs = argsreduce(cond, *((k,)+args))
 
3287
        insert(output,cond,self._cdf(*goodargs))
 
3288
        return output
 
3289
 
 
3290
    def sf(self,k,*args,**kwds):
 
3291
        """Survival function (1-cdf) at k of the given RV
 
3292
 
 
3293
        *args
 
3294
        =====
 
3295
        The shape parameter(s) for the distribution (see docstring of the
 
3296
           instance object for more information)
 
3297
        
 
3298
        **kwds
 
3299
        ======
 
3300
        loc   - location parameter (default=0)
 
3301
        """        
 
3302
        loc= kwds.get('loc')
 
3303
        args, loc = self.__fix_loc(args, loc)
 
3304
        k,loc = map(arr,(k,loc))
 
3305
        args = tuple(map(arr,args))
 
3306
        k = arr(k-loc)
 
3307
        cond0 = self._argcheck(*args) 
 
3308
        cond1 = (k >= self.a) & (k <= self.b)
 
3309
        cond2 = (k < self.a) & cond0
 
3310
        cond = cond0 & cond1
 
3311
        output = zeros(shape(cond),'d')
 
3312
        insert(output,(1-cond0)*(cond1==cond1),self.badvalue)
 
3313
        insert(output,cond2,1.0)
 
3314
        goodargs = argsreduce(cond, *((k,)+args))
 
3315
        insert(output,cond,self._sf(*goodargs))
 
3316
        return output
 
3317
 
 
3318
    def ppf(self,q,*args,**kwds):
 
3319
        """Percent point function (inverse of cdf) at q of the given RV
 
3320
 
 
3321
        *args
 
3322
        =====
 
3323
        The shape parameter(s) for the distribution (see docstring of the
 
3324
           instance object for more information)
 
3325
        
 
3326
        **kwds
 
3327
        ======
 
3328
        loc   - location parameter (default=0)
 
3329
        """                
 
3330
        loc = kwds.get('loc')
 
3331
        args, loc = self.__fix_loc(args, loc)
 
3332
        q,loc  = map(arr,(q,loc))
 
3333
        args = tuple(map(arr,args))
 
3334
        cond0 = self._argcheck(*args) & (loc == loc)
 
3335
        cond1 = (q > 0) & (q < 1)
 
3336
        cond2 = (q==1) & cond0
 
3337
        cond = cond0 & cond1
 
3338
        output = valarray(shape(cond),value=self.a-1)
 
3339
        insert(output,(1-cond0)*(cond1==cond1), self.badvalue)
 
3340
        insert(output,cond2,self.b)
 
3341
        goodargs = argsreduce(cond, *((q,)+args+(loc,)))
 
3342
        loc, goodargs = goodargs[-1], goodargs[:-1]
 
3343
        insert(output,cond,self._ppf(*goodargs) + loc)
 
3344
        return output
 
3345
        
 
3346
    def isf(self,q,*args,**kwds):
 
3347
        """Inverse survival function (1-sf) at q of the given RV
 
3348
 
 
3349
        *args
 
3350
        =====
 
3351
        The shape parameter(s) for the distribution (see docstring of the
 
3352
           instance object for more information)
 
3353
        
 
3354
        **kwds
 
3355
        ======
 
3356
        loc   - location parameter (default=0)
 
3357
        """        
 
3358
 
 
3359
        loc = kwds.get('loc')
 
3360
        args, loc = self.__fix_loc(args, loc)
 
3361
        q,loc  = map(arr,(q,loc))
 
3362
        args = tuple(map(arr,args))
 
3363
        cond0 = self._argcheck(*args) & (loc == loc)
 
3364
        cond1 = (q > 0) & (q < 1)
 
3365
        cond2 = (q==1) & cond0
 
3366
        cond = cond0 & cond1
 
3367
        output = valarray(shape(cond),value=self.b)
 
3368
        insert(output,(1-cond0)*(cond1==cond1), self.badvalue)
 
3369
        insert(output,cond2,self.a-1)
 
3370
        goodargs = argsreduce(cond, *((q,)+args+(loc,)))
 
3371
        loc, goodargs = goodargs[-1], goodargs[:-1]
 
3372
        insert(output,cond,self._ppf(*goodargs) + loc)
 
3373
        return output
 
3374
 
 
3375
    def stats(self, *args, **kwds):
 
3376
        """Some statistics of the given discrete RV
 
3377
 
 
3378
        *args
 
3379
        =====
 
3380
        The shape parameter(s) for the distribution (see docstring of the
 
3381
           instance object for more information)
 
3382
 
 
3383
        **kwds
 
3384
        ======
 
3385
        loc     - location parameter (default=0)
 
3386
        moments - a string composed of letters ['mvsk'] specifying
 
3387
                   which moments to compute (default='mv')
 
3388
                   'm' = mean,
 
3389
                   'v' = variance,
 
3390
                   's' = (Fisher's) skew,
 
3391
                   'k' = (Fisher's) kurtosis.
 
3392
        """        
 
3393
        loc,moments=map(kwds.get,['loc','moments'])
 
3394
        N = len(args)
 
3395
        if N > self.numargs:
 
3396
            if N == self.numargs + 1 and loc is None:  # loc is given without keyword
 
3397
                loc = args[-1]
 
3398
            if N == self.numargs + 2 and moments is None: # loc, scale, and moments
 
3399
                loc, moments = args[-2:]
 
3400
            args = args[:self.numargs]
 
3401
        if loc is None: loc = 0.0
 
3402
        if moments is None: moments = 'mv'
 
3403
                        
 
3404
        loc = arr(loc)
 
3405
        args = tuple(map(arr,args))
 
3406
        cond = self._argcheck(*args) & (loc==loc)
 
3407
 
 
3408
        signature = inspect.getargspec(self._stats.im_func)
 
3409
        if (signature[2] is not None) or ('moments' in signature[0]):
 
3410
            mu, mu2, g1, g2 = self._stats(*args,**{'moments':moments})
 
3411
        else:
 
3412
            mu, mu2, g1, g2 = self._stats(*args)
 
3413
        if g1 is None:
 
3414
            mu3 = None
 
3415
        else:
 
3416
            mu3 = g1*(mu2**1.5)
 
3417
        default = valarray(shape(cond), self.badvalue)
 
3418
        output = []
 
3419
 
 
3420
        # Use only entries that are valid in calculation
 
3421
        goodargs = argsreduce(cond, *(args+(loc,)))
 
3422
        loc, goodargs = goodargs[-1], goodargs[:-1]
 
3423
 
 
3424
        if 'm' in moments:
 
3425
            if mu is None:
 
3426
                mu = self._munp(1.0,*goodargs)
 
3427
            out0 = default.copy()
 
3428
            insert(out0,cond,mu+loc)
 
3429
            output.append(out0)
 
3430
            
 
3431
        if 'v' in moments:
 
3432
            if mu2 is None:
 
3433
                mu2p = self._munp(2.0,*goodargs)
 
3434
                if mu is None:
 
3435
                    mu = self._munp(1.0,*goodargs)
 
3436
                mu2 = mu2p - mu*mu
 
3437
            out0 = default.copy()
 
3438
            insert(out0,cond,mu2)
 
3439
            output.append(out0)
 
3440
            
 
3441
        if 's' in moments:
 
3442
            if g1 is None:
 
3443
                mu3p = self._munp(3.0,*goodargs)
 
3444
                if mu is None:
 
3445
                    mu = self._munp(1.0,*goodargs)                    
 
3446
                if mu2 is None:
 
3447
                    mu2p = self._munp(2.0,*goodargs)
 
3448
                    mu2 = mu2p - mu*mu
 
3449
                mu3 = mu3p - 3*mu*mu2 - mu**3
 
3450
                g1 = mu3 / mu2**1.5
 
3451
            out0 = default.copy()
 
3452
            insert(out0,cond,g1)
 
3453
            output.append(out0)
 
3454
                
 
3455
        if 'k' in moments:
 
3456
            if g2 is None:
 
3457
                mu4p = self._munp(4.0,*goodargs)
 
3458
                if mu is None:
 
3459
                    mu = self._munp(1.0,*goodargs)                    
 
3460
                if mu2 is None:
 
3461
                    mu2p = self._munp(2.0,*goodargs)
 
3462
                    mu2 = mu2p - mu*mu
 
3463
                if mu3 is None:
 
3464
                    mu3p = self._munp(3.0,*goodargs)
 
3465
                    mu3 = mu3p - 3*mu*mu2 - mu**3 
 
3466
                mu4 = mu4p - 4*mu*mu3 - 6*mu*mu*mu2 - mu**4
 
3467
                g2 = mu4 / mu2**2.0 - 3.0
 
3468
            out0 = default.copy()
 
3469
            insert(out0,cond,g2)
 
3470
            output.append(out0)
 
3471
 
 
3472
        if len(output) == 1:
 
3473
            return output[0]
 
3474
        else:
 
3475
            return tuple(output)
 
3476
 
 
3477
    def moment(self, n, *args, **kwds):   # Non-central moments in standard form.
 
3478
        if (floor(n) != n):
 
3479
            raise ValueError, "Moment must be an integer."
 
3480
        if (n < 0): raise ValueError, "Moment must be positive."
 
3481
        if (n == 0): return 1.0
 
3482
        if (n > 0) and (n < 5):
 
3483
            signature = inspect.getargspec(self._stats.im_func)
 
3484
            if (signature[2] is not None) or ('moments' in signature[0]):
 
3485
                dict = {'moments':{1:'m',2:'v',3:'vs',4:'vk'}[n]}
 
3486
            else:
 
3487
                dict = {}
 
3488
            mu, mu2, g1, g2 = self._stats(*args,**dict)
 
3489
            if (n==1):
 
3490
                if mu is None: return self._munp(1,*args)
 
3491
                else: return mu
 
3492
            elif (n==2):
 
3493
                if mu2 is None: return self._munp(2,*args)
 
3494
                else: return mu
 
3495
            elif (n==3):
 
3496
                if g1 is None or mu2 is None: return self._munp(3,*args)
 
3497
                else: return g1*(mu2**1.5)
 
3498
            else: # (n==4)
 
3499
                if g2 is None or mu2 is None: return self._munp(4,*args)
 
3500
                else: return (g2+3.0)*(mu2**2.0)
 
3501
        else:
 
3502
            return self._munp(n,*args)
 
3503
 
 
3504
    def freeze(self, *args, **kwds):
 
3505
        return rv_frozen(self, *args, **kwds)
 
3506
 
 
3507
    def _entropy(self, *args):
 
3508
        if hasattr(self,'pk'):
 
3509
            return entropy(self.pk)
 
3510
        else:
 
3511
            mu = int(self.stats(*args, **{'moments':'m'}))
 
3512
            val = self.pmf(mu,*args)
 
3513
            if (val==0.0): ent = 0.0
 
3514
            else: ent = -val*log(val)
 
3515
            k = 1
 
3516
            term = 1.0
 
3517
            while (abs(term) > eps):
 
3518
                val = self.pmf(mu+k,*args)
 
3519
                if val == 0.0: term = 0.0
 
3520
                else: term = -val * log(val)
 
3521
                val = self.pmf(mu-k,*args)
 
3522
                if val != 0.0: term -= val*log(val)
 
3523
                k += 1
 
3524
                ent += term
 
3525
            return ent
 
3526
 
 
3527
    def entropy(self, *args, **kwds):
 
3528
        loc= kwds.get('loc')
 
3529
        args, loc = self.__fix_loc(args, loc)
 
3530
        loc = arr(loc)
 
3531
        args = map(arr,args)
 
3532
        cond0 = self._argcheck(*args) & (loc==loc)
 
3533
        output = zeros(shape(cond0),'d')
 
3534
        insert(output,(1-cond0),self.badvalue)
 
3535
        goodargs = argsreduce(cond0, *args)
 
3536
        insert(output,cond0,self.vecentropy(*goodargs))
 
3537
        return output
 
3538
 
 
3539
    def __call__(self, *args, **kwds):
 
3540
        return self.freeze(*args,**kwds)
 
3541
    
 
3542
# Binomial
 
3543
 
 
3544
class binom_gen(rv_discrete):
 
3545
    def _rvs(self, n, pr):
 
3546
        return rand.binomial(n,pr,self._size)
 
3547
    def _argcheck(self, n, pr):
 
3548
        self.b = n
 
3549
        return (n>=0) & (pr >= 0) & (pr <= 1)
 
3550
    def _cdf(self, x, n, pr):
 
3551
        k = floor(x)
 
3552
        vals = special.bdtr(k,n,pr)
 
3553
        return vals
 
3554
    def _sf(self, x, n, pr):
 
3555
        k = floor(x)
 
3556
        return special.bdtrc(k,n,pr)
 
3557
    def _ppf(self, q, n, pr):
 
3558
        vals = ceil(special.bdtrik(q,n,pr))
 
3559
        vals1 = vals-1
 
3560
        temp = special.bdtr(vals1,n,pr)
 
3561
        return where(temp >= q, vals1, vals)
 
3562
    def _stats(self, n, pr):
 
3563
        q = 1.0-pr
 
3564
        mu = n * pr
 
3565
        var = n * pr * q
 
3566
        g1 = (q-pr) / sqrt(n*pr*q)
 
3567
        g2 = (1.0-6*pr*q)/(n*pr*q)
 
3568
        return mu, var, g1, g2
 
3569
    def _entropy(self, n, pr):
 
3570
        k = r_[0:n+1]
 
3571
        vals = self._pmf(k,n,pr)
 
3572
        lvals = where(vals==0,0.0,log(vals))
 
3573
        return -sum(vals*lvals)
 
3574
binom = binom_gen(name='binom',shapes="n,pr",extradoc="""
 
3575
 
 
3576
Binomial distribution
 
3577
 
 
3578
   Counts the number of successes in *n* independent
 
3579
   trials when the probability of success each time is *pr*.
 
3580
""")
 
3581
 
 
3582
# Bernoulli distribution
 
3583
 
 
3584
class bernoulli_gen(binom_gen):
 
3585
    def _rvs(self, pr):
 
3586
        return binom_gen._rvs(self, 1, pr)
 
3587
    def _argcheck(self, pr):
 
3588
        return (pr >=0 ) & (pr <= 1)
 
3589
    def _cdf(self, x, pr):
 
3590
        return binom_gen._cdf(self, x, 1, pr)
 
3591
    def _sf(self, x, pr):
 
3592
        return binom_gen._sf(self, x, 1, pr)
 
3593
    def _ppf(self, q, pr):
 
3594
        return binom_gen._ppf(self, q, 1, pr)
 
3595
    def _stats(self, pr):
 
3596
        return binom_gen._stats(self, 1, pr)
 
3597
    def _entropy(self, pr):
 
3598
        return -pr*log(pr)-(1-pr)*log(1-pr)
 
3599
bernoulli = bernoulli_gen(b=1,name='bernoulli',shapes="pr",extradoc="""
 
3600
 
 
3601
Bernoulli distribution
 
3602
 
 
3603
   1 if binary experiment succeeds, 0 otherwise.  Experiment
 
3604
   succeeds with probabilty *pr*.
 
3605
"""
 
3606
)
 
3607
 
 
3608
# Negative binomial
 
3609
class nbinom_gen(rv_discrete):
 
3610
    def _rvs(self, n, pr):
 
3611
        return rand.negative_binomial(n, pr, self._size)
 
3612
    def _argcheck(self, n, pr):
 
3613
        return (n >= 0) & (pr >= 0) & (pr <= 1)
 
3614
    def _cdf(self, x, n, pr):
 
3615
        k = floor(x)
 
3616
        return special.nbdtr(k,n,pr)
 
3617
    def _sf(self, x, n, pr):
 
3618
        k = floor(x)
 
3619
        return special.nbdtrc(k,n,pr)
 
3620
    def _ppf(self, q, n, pr):
 
3621
        vals = ceil(special.nbdtrik(q,n,pr))
 
3622
        vals1 = vals-1
 
3623
        temp = special.nbdtr(vals1,n,pr)
 
3624
        return where(temp >= q, vals1, vals)
 
3625
    def _stats(self, n, pr):
 
3626
        Q = 1.0 / pr
 
3627
        P = Q - 1.0
 
3628
        mu = n*P
 
3629
        var = n*P*Q
 
3630
        g1 = (Q+P)/sqrt(n*P*Q)
 
3631
        g2 = (1.0 + 6*P*Q) / (n*P*Q)
 
3632
        return mu, var, g1, g2
 
3633
nbinom = nbinom_gen(name='nbinom', longname="A negative binomial",
 
3634
                    shapes="n,pr", extradoc="""
 
3635
 
 
3636
Negative binomial distribution
 
3637
"""
 
3638
                    )
 
3639
 
 
3640
## Geometric distribution
 
3641
 
 
3642
class geom_gen(rv_discrete):
 
3643
    def _rvs(self, pr):
 
3644
        return rv._inst._geom(pr,size=(self._size,))
 
3645
    def _argcheck(self, pr):
 
3646
        return (pr<=1) & (pr >= 0)
 
3647
    def _pmf(self, k, pr):
 
3648
        return (1-pr)**k * pr
 
3649
    def _cdf(self, x, pr):
 
3650
        k = floor(x)
 
3651
        return (1.0-(1.0-pr)**k)
 
3652
    def _sf(self, x, pr):
 
3653
        k = floor(x)
 
3654
        return (1.0-pr)**k
 
3655
    def _ppf(self, q, pr):
 
3656
        vals = ceil(log(1.0-q)/log(1-pr))
 
3657
        temp = 1.0-(1.0-pr)**(vals-1)
 
3658
        return where((temp >= q) & (vals > 0), vals-1, vals)
 
3659
    def _stats(self, pr):        
 
3660
        mu = 1.0/pr
 
3661
        qr = 1.0-pr
 
3662
        var = qr / pr / pr
 
3663
        g1 = (2.0-pr) / sqrt(qr)
 
3664
        g2 = scipy.polyval([1,-6,6],pr)/(1.0-pr)
 
3665
        return mu, var, g1, g2
 
3666
geom = geom_gen(a=1,name='geom', longname="A geometric",
 
3667
                shapes="pr", extradoc="""
 
3668
 
 
3669
Geometric distribution
 
3670
"""
 
3671
                )
 
3672
 
 
3673
## Hypergeometric distribution
 
3674
 
 
3675
class hypergeom_gen(rv_discrete):
 
3676
    def _rvs(self, M, n, N):
 
3677
        return rv._inst._hypergeom(M,n,N,size=(self._size,))
 
3678
    def _argcheck(self, M, n, N):
 
3679
        cond = rv_discrete._argcheck(self,M,n,N)
 
3680
        cond &= (n <= M) & (N <= M)
 
3681
        self.a = N-(M-n)
 
3682
        self.b = min(n,N)
 
3683
        return cond
 
3684
    def _pmf(self, k, M, n, N):
 
3685
        tot, good = M, n
 
3686
        comb = scipy.comb
 
3687
        bad = tot - good
 
3688
        return comb(good,k) * comb(bad,N-k) / comb(tot,N)
 
3689
    def _stats(self, M, n, N):
 
3690
        tot, good = M, n
 
3691
        n = good*1.0
 
3692
        m = (tot-good)*1.0
 
3693
        N = N*1.0
 
3694
        tot = m+n
 
3695
        p = n/tot
 
3696
        mu = N*p
 
3697
        var = m*n*N*(tot-N)*1.0/(tot*tot*(tot-1))
 
3698
        g1 = (m - n)*(tot-2*N) / (tot-2.0)*sqrt((tot-1.0)/(m*n*N*(tot-N)))
 
3699
        m2, m3, m4, m5 = m**2, m**3, m**4, m**5
 
3700
        n2, n3, n4, n5 = n**2, n**2, n**4, n**5
 
3701
        g2 = m3 - m5 + n*(3*m2-6*m3+m4) + 3*m*n2 - 12*m2*n2 + 8*m3*n2 + n3 \
 
3702
             - 6*m*n3 + 8*m2*n3 + m*n4 - n5 - 6*m3*N + 6*m4*N + 18*m2*n*N \
 
3703
             - 6*m3*n*N + 18*m*n2*N - 24*m2*n2*N - 6*n3*N - 6*m*n3*N \
 
3704
             + 6*n4*N + N*N*(6*m2 - 6*m3 - 24*m*n + 12*m2*n + 6*n2 + \
 
3705
                             12*m*n2 - 6*n3)
 
3706
        return mu, var, g1, g2
 
3707
    def _entropy(self, M, n, N):
 
3708
        k = r_[N-(M-n):min(n,N)+1]
 
3709
        vals = self.pmf(k,M,n,N)
 
3710
        lvals = where(vals==0.0,0.0,log(vals))
 
3711
        return -sum(vals*lvals)
 
3712
hypergeom = hypergeom_gen(name='hypergeom',longname="A hypergeometric",
 
3713
                          shapes="M,n,N", extradoc="""
 
3714
 
 
3715
Hypergeometric distribution
 
3716
 
 
3717
   Models drawing objects from a bin. 
 
3718
   M is total number of objects, n is total number of Type I objects.
 
3719
   RV counts number of Type I objects in N drawn without replacement from
 
3720
   population.
 
3721
"""
 
3722
                          )
 
3723
 
 
3724
## Logarithmic (Log-Series), (Series) distribution
 
3725
 
 
3726
class logser_gen(rv_discrete):
 
3727
    def _rvs(self, pr):
 
3728
        return rv._inst._logser(pr,size=(self._size,))
 
3729
    def _argcheck(self, pr):
 
3730
        return (pr > 0) & (pr < 1)
 
3731
    def _pmf(self, k, pr):
 
3732
        return -pr**k * 1.0 / k / log(1-pr)
 
3733
    def _stats(self, pr):
 
3734
        r = log(1-pr)
 
3735
        mu = pr / (pr - 1.0) / r
 
3736
        mu2p = -pr / r / (pr-1.0)**2
 
3737
        var = mu2p - mu*mu
 
3738
        mu3p = -pr / r * (1.0+pr) / (1.0-pr)**3
 
3739
        mu3 = mu3p - 3*mu*mu2p + 2*mu**3
 
3740
        g1 = mu3 / var**1.5
 
3741
 
 
3742
        mu4p = -pr / r * (1.0/(pr-1)**2 - 6*pr/(pr-1)**3 + \
 
3743
                          6*pr*pr / (pr-1)**4)
 
3744
        mu4 = mu4p - 4*mu3p*mu + 6*mu2p*mu*mu - 3*mu**4
 
3745
        g2 = mu4 / var**2 - 3.0
 
3746
        return mu, var, g1, g2
 
3747
logser = logser_gen(a=1,name='logser', longname='A logarithmic',
 
3748
                    shapes='pr', extradoc="""
 
3749
 
 
3750
Logarithmic (Log-Series, Series) distribution
 
3751
"""
 
3752
                    )
 
3753
 
 
3754
## Poisson distribution
 
3755
 
 
3756
class poisson_gen(rv_discrete):
 
3757
    def _rvs(self, mu):
 
3758
        return rand.poisson(mu, self._size)
 
3759
    def _pmf(self, k, mu):
 
3760
        Pk = mu**k * exp(-mu) / arr(special.gamma(k+1))
 
3761
        return Pk
 
3762
    def _cdf(self, x, mu):
 
3763
        k = floor(x)
 
3764
        return special.pdtr(k,mu)
 
3765
    def _sf(self, x, mu):
 
3766
        k = floor(x)
 
3767
        return special.pdtrc(k,mu)
 
3768
    def _ppf(self, q, mu):
 
3769
        vals = ceil(special.pdtrik(q,mu))
 
3770
        temp = special.pdtr(vals-1,mu)
 
3771
        return where((temp >= q), vals1, vals)
 
3772
    def _stats(self, mu):
 
3773
        var = mu
 
3774
        g1 = 1.0/arr(sqrt(mu))
 
3775
        g2 = 1.0 / arr(mu)
 
3776
        return mu, var, g1, g2
 
3777
poisson = poisson_gen(name="poisson", longname='A Poisson',
 
3778
                      shapes="mu", extradoc="""
 
3779
 
 
3780
Poisson distribution
 
3781
"""
 
3782
                      )
 
3783
 
 
3784
## (Planck) Discrete Exponential 
 
3785
 
 
3786
class planck_gen(rv_discrete):
 
3787
    def _argcheck(self, lambda_):
 
3788
        if (lambda_ > 0):
 
3789
            self.a = 0
 
3790
            self.b = inf
 
3791
            return 1
 
3792
        elif (lambda_ < 0):
 
3793
            self.a = -inf
 
3794
            self.b = 0
 
3795
            return 1
 
3796
        return 0  # lambda_ = 0
 
3797
    def _pmf(self, k, lambda_):
 
3798
        fact = (1-exp(-lamba))
 
3799
        return fact*exp(-lambda_(k))
 
3800
    def _cdf(self, x, lambda_):
 
3801
        k = floor(x)
 
3802
        return 1-exp(-lambda_*(k+1))
 
3803
    def _ppf(self, q, lambda_):
 
3804
        val = ceil(-1.0/lambda_ * log(1-q)-1)
 
3805
        return val
 
3806
    def _stats(self, lambda_):
 
3807
        mu = 1/(exp(lambda_)-1)
 
3808
        var = exp(-lambda_)/(1-exp(-lambda_))**2
 
3809
        g1 = 2*cosh(lambda_/2.0)
 
3810
        g2 = 4+2*cosh(lambda_)
 
3811
        return mu, var, g1, g2
 
3812
    def _entropy(self, lambda_):
 
3813
        l = lambda_
 
3814
        C = (1-exp(-l))
 
3815
        return l*exp(-l)/C - log(C)
 
3816
planck = planck_gen(name='planck',longname='A discrete exponential ',
 
3817
                    shapes="lambda_",
 
3818
                    extradoc="""
 
3819
 
 
3820
Planck (Discrete Exponential)
 
3821
 
 
3822
    pmf is p(k; b) = (1-exp(-b))*exp(-b*k) for kb >= 0
 
3823
"""
 
3824
                      )
 
3825
 
 
3826
class boltzmann_gen(rv_discrete):
 
3827
    def _pmf(self, k, lambda_, N):
 
3828
        fact = (1-exp(-lambda_))/(1-exp(-lambda_*N))
 
3829
        return fact*exp(-lambda_(k))
 
3830
    def _cdf(self, x, lambda_, N):
 
3831
        k = floor(x)
 
3832
        return (1-exp(-lambda_*(k+1)))/(1-exp(-lambda_*N))
 
3833
    def _ppf(self, q, lambda_, N):
 
3834
        qnew = q*(1-exp(-lambda_*N))
 
3835
        val = ceil(-1.0/lambda_ * log(1-qnew)-1)
 
3836
        return val
 
3837
    def _stats(self, lambda_, N):
 
3838
        z = exp(-lambda_)
 
3839
        zN = exp(-lambda_*N)
 
3840
        mu = z/(1.0-z)-N*zN/(1-zN)
 
3841
        var = z/(1.0-z)**2 - N*N*zN/(1-zN)**2
 
3842
        trm = (1-zN)/(1-z)
 
3843
        trm2 = (z*trm**2 - N*N*zN)
 
3844
        g1 = z*(1+z)*trm**3 - N**3*zN*(1+zN)
 
3845
        g1 = g1 / trm2**(1.5)
 
3846
        g2 = z*(1+4*z+z*z)*trm**4 - N**4 * zN*(1+4*zN+zN*zN)
 
3847
        g2 = g2 / trm2 / trm2
 
3848
        return mu, var, g1, g2
 
3849
 
 
3850
boltzmann = boltzmann_gen(name='boltzmann',longname='A truncated discrete exponential ',
 
3851
                    shapes="lambda_,N",
 
3852
                    extradoc="""
 
3853
 
 
3854
Boltzmann (Truncated Discrete Exponential)
 
3855
 
 
3856
    pmf is p(k; b, N) = (1-exp(-b))*exp(-b*k)/(1-exp(-b*N)) for k=0,..,N-1
 
3857
"""
 
3858
                      )
 
3859
 
 
3860
 
 
3861
 
 
3862
 
 
3863
## Discrete Uniform
 
3864
 
 
3865
class randint_gen(rv_discrete):
 
3866
    def _argcheck(self, min, max):
 
3867
        self.a = min
 
3868
        self.b = max-1
 
3869
        return (max > min)
 
3870
    def _pmf(self, k, min, max):
 
3871
        fact = 1.0 / (max - min)
 
3872
        return fact
 
3873
    def _cdf(self, x, min, max):
 
3874
        k = floor(x)
 
3875
        return (k-min+1)*1.0/(max-min)
 
3876
    def _ppf(self, q, min, max):
 
3877
        val = ceil(q*(max-min)+min)
 
3878
        return val
 
3879
    def _stats(self, min, max):
 
3880
        m2, m1 = arr(max), arr(min)
 
3881
        mu = (m2 + m1 - 1.0) / 2
 
3882
        d = m2 - m1
 
3883
        var = (d-1)*(d+1.0)/12.0
 
3884
        g1 = 0.0
 
3885
        g2 = -6.0/5.0*(d*d+1.0)/(d-1.0)*(d+1.0)
 
3886
        return mu, var, g1, g2
 
3887
    def rvs(self, min, max=None, size=None):
 
3888
        """An array of *size* random integers >= min and < max.
 
3889
    
 
3890
        If max is None, then range is >=0  and < min
 
3891
        """
 
3892
        if max is None:
 
3893
            max = min
 
3894
            min = 0
 
3895
        U = random(size=size)
 
3896
        val = floor((max-min)*U + min)
 
3897
        return arr(val).astype(Num.Int)
 
3898
    def _entropy(self, min, max):
 
3899
        return log(max-min)
 
3900
randint = randint_gen(name='randint',longname='A discrete uniform '\
 
3901
                      '(random integer)', shapes="min,max",
 
3902
                      extradoc="""
 
3903
 
 
3904
Discrete Uniform
 
3905
 
 
3906
    Random integers >=min and <max.
 
3907
"""
 
3908
                      )
 
3909
 
 
3910
 
 
3911
# Zipf distribution
 
3912
 
 
3913
class zipf_gen(rv_discrete):
 
3914
    def _rvs(self, a):
 
3915
        return rv._inst._Zipf(a, size=(self._size,))
 
3916
    def _argcheck(self, a):
 
3917
        return a > 1
 
3918
    def _pmf(self, k, a):
 
3919
        Pk = 1.0 / arr(special.zeta(a,1) * k**a)
 
3920
        return Pk
 
3921
    def _munp(self, n, a):
 
3922
        return special.zeta(a-n,1) / special.zeta(a,1)
 
3923
    def _stats(self, a):
 
3924
        sv = errp(0)
 
3925
        fac = arr(special.zeta(a,1))
 
3926
        mu = special.zeta(a-1.0,1)/fac
 
3927
        mu2p = special.zeta(a-2.0,1)/fac
 
3928
        var = mu2p - mu*mu
 
3929
        mu3p = special.zeta(a-3.0,1)/fac
 
3930
        mu3 = mu3p - 3*mu*mu2p + 2*mu**3
 
3931
        g1 = mu3 / arr(var**1.5)
 
3932
        
 
3933
        mu4p = special.zeta(a-4.0,1)/fac
 
3934
        sv = errp(sv)
 
3935
        mu4 = mu4p - 4*mu3p*mu + 6*mu2p*mu*mu - 3*mu**4
 
3936
        g2 = mu4 / arr(var**2) - 3.0
 
3937
        return mu, var, g1, g2
 
3938
zipf = zipf_gen(a=1,name='zipf', longname='A Zipf',
 
3939
                shapes="a", extradoc="""
 
3940
 
 
3941
Zipf distribution
 
3942
"""
 
3943
                )
 
3944
                
 
3945
 
 
3946
# Discrete Laplacian
 
3947
 
 
3948
class dlaplace_gen(rv_discrete):
 
3949
    def _pmf(self, k, a):
 
3950
        return tanh(a/2.0)*exp(-a*abs(k))
 
3951
    def _cdf(self, x, a):
 
3952
        k = floor(x)
 
3953
        ind = (k >= 0)
 
3954
        const = exp(a)+1
 
3955
        return where(ind, 1.0-exp(-a*k)/const, exp(a*(k+1))/const)
 
3956
    def _ppf(self, q, a):
 
3957
        const = 1.0/(1+exp(-a))
 
3958
        cons2 = 1+exp(a)
 
3959
        ind = q < const
 
3960
        return ceil(1.0/a*where(ind, log(q*cons2)-1, -log((1-q)*cons2)))
 
3961
    def _stats(self, a):
 
3962
        ea = exp(-a)
 
3963
        e2a = exp(-2*a)
 
3964
        e3a = exp(-3*a)
 
3965
        e4a = exp(-4*a)
 
3966
        mu2 = 2* (e2a + ea) / (1-ea)**3.0
 
3967
        mu4 = 2* (e4a + 11*e3a + 11*e2a + ea) / (1-ea)**5.0
 
3968
        return 0.0, mu2, 0.0, mu4 / mu2**2.0 - 3
 
3969
    def _entropy(self, a):
 
3970
        return a / sinh(a) - log(tanh(a/2.0))
 
3971
dlaplace = dlaplace_gen(a=-inf,
 
3972
                        name='dlaplace', longname='A discrete Laplacian',
 
3973
                        shapes="a", extradoc="""
 
3974
                        
 
3975
Discrete Laplacian distribution. 
 
3976
"""
 
3977
                        )
 
3978