Repository: scipy/scipy

Issue:
vonmises and vonmises_line in stats: vonmises wrong and superfluous?
Two distributions are currently implemented in `scipy.stats`: `vonmises` and `vonmises_line`.

https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.vonmises.html
https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.vonmises_line.html

According to Wikipedia (https://en.wikipedia.org/wiki/Von_Mises_distribution), the von Mises distribution is defined on [-pi, pi] (in the standard form).

`vonmises` is defined on the real line
`vonmises_line` is defined on [-pi, pi]

I don't think the implemention of `vonmises` makes sense. For instance, the `pdf` returns `np.exp(kappa * np.cos(x)) / (2*np.pi*sc.i0(kappa))` which does not converge to zero as `x` goes to infinity. The cdf also does not return sensible values, see below.

Should there only be one vonmises distribution?

### Reproducing code example:
```
from scipy import stats
vm = stats.vonmises(1)
vm.cdf(10) # 2.0281170964731907
```

### Scipy/Numpy/Python version information:
```
1.0.0 1.14.1 sys.version_info(major=3, minor=5, micro=4, releaselevel='final', serial=0)
```



Discussion:
The doc is also the same for both distributions, which is confusing to a reader.  But perhaps not surprising given `scipy/stats/_continuous_distns.py:6156-6157`
```
vonmises = vonmises_gen(name='vonmises')
vonmises_line = vonmises_gen(a=-np.pi, b=np.pi, name='vonmises_line')
```

It appears that the `cdf` is almost a periodic function:
`vm.cdf(x+2*np.pi) ==  vm.cdf(x) + 1`
So the x-values are converted to the [-pi, pi] range, but the value returned for the cdf doesn't wrap in any way.
The "improper" vonmises is convenient for working with it as a circular distribution, given that there is no special support.
The advantage is that every interval with length 2 pi can be used as basis for the circular vonmises distribution. Using fixed limits like [-pi, pi] makes it difficult to shift the mean/center around the circle.

similar issue #4598

a long time (4 to 6 years) ago, Robert Cimrman and I estimated mixtures of vonmises distributions.
Anne Archibald had added the extended cdf.


Which one is the "improper" one?  `vonmises`? If so then there is somewhat of a disconnect.
The "standard" Von Mises is implemented as `vonmises_line`.
The "improper" Von Mises is implemented as `vonmises`, but that is not actually a probability distribution.
 * `vonmises.cdf(-np.inf) = 0`, but `vonmises.cdf(x) ~ x/2pi` as `x -> -infinity`
* `vonmises.cdf(np.inf) = 1`, but `vonmises.cdf(x) ~ x/2pi` as `x -> infinity`
* The `cdf()` computations on the improper can make sense whenever taking the difference of two `cdf()`s, and the two `x`-values are within `2pi` of each other.  
But none of this is in the doc.
I suspect this is going to keep puzzling people year after year until there is a proper circular distribution framework alongside `rv_continuous`.
I agree with pvanmulbregt that it ist confusing to call the distribution on [-pi, pi] `vonmises_line`.

I also don't understand the issue of defining the distribution on [-pi,pi] only. If one wants to evaluate the pdf / cdf at `x` where `x` is not necessarily in that interval, one would just need to map it before the pdf / cdf is applied, no?
And using `scale` and `loc`, one can define the distribution on any bounded interval [a, b]. i don't know circular distributions well, so maybe i misunderstand something....
The current generic scale and loc handling doesn't work correctly for circular distribution, e.g. loc shifts the domain with the distribution, which means that the center within the shifted interval didn't change.

Neither of the distribution makes a lot of sense out of the box
vonmises_line was added so we have a proper distribution on fixed interval, but for vonmises it would need a shape parameter to rotate it within this interval, I guess.
vonmises works fine as circular distribution, but it leaves it to the user to handle at which interval cdf, pdf and other methods should be evaluated. 
Also circular moments are defined differently from moments on an interval.

> If one wants to evaluate the pdf / cdf at x where x is not necessarily in that interval, one would just need to map it before the pdf / cdf is applied, no?

I don't remember if I tried that. AFAIR, I needed to use a lot of modulo `2 pi` to shift the values to get unique parameters or somthing, given the periodic behavior when the circular definition is expanded to the real line.
One problem with the inherited generic behavior is that users can change the domain if they use loc and scale and the code would have to map into the shifted/dilated domain or prevent users from using loc and scale, and add circular loc and circular dispersion as shape parameters.

(based on my maybe imperfect memory)
What might work is to make vonmises or vonmises_line into a 4 parameter distribution with 2 shape parameters, circular mean and circular dispersion, on a fixed interval [-pi, pi] that internally evaluated pdf for the correct shape given by vonmises on a shifted segment.

Users could keep loc and scale fixed, or for example use it to translate the circle to a 24 hour clock, i.e. interval [0, 24).

That might be pretty much the steps that a user needs to do currently to use vonmises as a circular distribution.
Do you have an online reference for circular distributions that you recommend?
No, or I don't remember,
My main reference was Mardia's book on Directional Statistics, otherwise I was reading articles on specific distribution families or methods like wrapping to construct those families, and most likely skimmed or selectively read some other books.

Maybe https://en.wikipedia.org/wiki/Directional_statistics#von_Mises_circular_distribution has some useful links


Thanks. That makes it seem as though the usual concept of CDF from 1-d real (or real interval) distributions doesn't make sense in the circular world. There is no ordering on the domain, hence no natural endpoints, no `a`, `b` as used in `rv_continuous`.  But the measure of a circular interval `[Theta0, Theta1]` makes sense, as just the integral of the PDF between the two endpoint angles.  My interpretation of your earlier comments is that you may have used the difference `vonmises.cdf(kappa, Theta1) - vonmises.cdf(kappa, Theta0)` to calculate that measure.  Is that correct?
> My interpretation of your earlier comments is that you may have used the difference vonmises.cdf(kappa, Theta1) - vonmises.cdf(kappa, Theta0) to calculate that measure. Is that correct?

Yes, because cdf of vonmises is trend + periodic term, only definite integrals make sense, i.e. there is no fixed origin with cdf = 0 that is relevant for any specific (shifted) problem. 
It's like going round and round the circle, but we only want to measure distances for the last circle, while our step counter (cdf) is measuring from some initial location. 
I wondered how tied `vonmises` is to [-pi, pi] so I created 2 other `vonmises_line` distributions with a longer interval, and a shifted interval:
`vonmises_line2  = vonmises_gen(a=-2*np.pi, b=2*np.pi, name='vonmises_line2')`
`vonmises_line3  = vonmises_gen(a=0, b=2*np.pi, name='vonmises_line3')`
analogous to the original
`vonmises_line = vonmises_gen(a=-np.pi, b=np.pi, name='vonmises_line')`
and plotted the CDFs.

![image](https://user-images.githubusercontent.com/23403152/40689646-1ba07cc2-6371-11e8-9f99-5b0891291dbb.png)

Looks like the only interval supported is `[-pi, pi]`. The length must be `2pi` and it must be centered at 0.  Any other interval would need to be handled by using `loc` and `scale`.
My understanding from this is that a circular distribution framework would have:
- The PDF is repeating non-negative function with period `2pi`and `integral_{-pi}^{pi} PDF(x) = 1`
- The CDF is monotonically increasing, with `CDF(x+2pi) = CDF(x) +1`.  In particular, it will take negative values, and values bigger than 1. 
- The PPF's domain would not be restricted to `[0, 1]`. 
- Some "standard" functions in `rv_generic` wouldn't make a lot of sense in the circular framework.
Something like the plot below (vonMises with kappa=1)
[Added ppf plot]
![image](https://user-images.githubusercontent.com/23403152/40843193-3571a32e-657e-11e8-9e62-b317287f23bf.png)

Is that correct?
The first two are correct for sure. 
Aside to get one full rotation we would need only 2 cycles in the periodic pdf, cdf

I don't remember about the other two, I might not have really used rvs and ppf (I'm pretty sure I didn't look specifically at np.random.vonmises):

> The PPF's domain would not be restricted to [0, 1].
> Some "standard" functions in rv_generic wouldn't make a lot of sense in the circular framework.
Something like the plot below (vonMises with kappa=1)

My guess is to create rvs for vonmises we need a "proper" ppf, i.e. we should use vonmises_line and rotate, i.e. use a shift and a modulo transform, or transform ppf to map from [0, 1] to some interval of length 2 * pi if we want the generic `rvs = ppf(rvs_uniform)` transformation.
I meant `rv_generic` in a different sense.  The class hierarchy is
```
rv_frozen
rv_generic ---- rv_discrete --- binom_gen
        |                |----- bernoulli_gen
        |                |----- ...
        |
        |------ rv_continuous --- norm_gen
                           |----- beta_gen
                           |----- ...

multi_rv_frozen
multi_rv_generic  --- multivariate_normal_gen
              | ----- dirichlet_gen
```
I was thinking about where to place `rv_circular` and what functionality it would have.
`rv_generic` contains useful functionality relating to arg checking and frozen distributions, but also includes methods which may not make sense for circular distributions.  E.g `_logcdf`, `_sf`, `_logsf`, `_isf`, `_stats`, `_stats`.  Others may have potentially different meanings `mean`, `std`, `var`. It may even need its own `rv_circular_frozen` as `rv_frozen` exposes `sf`, `stats` etc.
`rv_circular` could be a derived class of `rv_generic` with many methods set to `None`. It could be its own class with methods cloned from `rv_generic`.  Or pull the most generic functionality out of `rv_generic` into `rv_base` and have `rv_generic` derive from that. 

What circular distributions do you see needing in practice?
Uniform? von Mises? Wrapped Normal? Wrapped Cauchy? Wrapped Levy? All these?  Others?
Just 1-dimensional? Or on higher dimensional spheres (or even tori)?  [It looks like these higher dimensional cases are sufficiently different to treat separately and not consider at this time.]

AFAIR, I never thought about what a full circular distribution class should look like, I was mainly working with pdf, cdf and characteristic function.

Higher dimensional spheres would require multivariate distributions and not fit directly into the same setting as univariate circular distributions.

AFAIR, the main intuition for implementing parts of the distribution is to map it to a fixed interval, e.g. [0, 2*pi] and translate everything into that space. 
We still need an origin to fix the meaning of the measurements, and observations are usually in the interval, E.g. a 24 hour clock starts at 0 and ends at 24  (excluding 24), time is measured on this scale, and the distribution is over those 24 hours.
The main point to take into account is that distances are not on the interval, e.g. 23.5 is close to 0.5, and we don't want a jump at 0. 
ppf could be defined on this fixed interval, e.g. for use in rvs.
However, the median is defined differently and would not be ppf(0.5) in this definition.
isf can be defined in the same way as cdf but with a negative trend, i.e. only definite integrals to a fixed endpoint make sense.

The other option is to define everything possible in terms of periodic functions, e.g. pdf and moments are defined in terms of complex exponential or sin/cos.

Aside: besides full circular data, data can also be undirected in the sense that we don't know if it's looking forward or backward, e.g. we cannot distinguish 3am from 3pm if we only know it's 3 o'clock in the US. In the application that we worked on, we had data for 0 to 180 degrees (which is equivalent to having 180 to 360 degree data, objects didn't have distinguishable head and tail).

summary: 
I was thinking in pretty eclectic ways about this, using for each case whatever was convenient or made sense to me, but I didn't have to bring everything into a consistent implementation. i.e. I was jumping between periodic functions and working with modulo on an interval pretty "arbitrarily".

I think for designing circular distribution it would be helpful to look at astropy or ask those developers. Astronomy is one of the main application areas for circular distributions that I know of.
(but they also use `units` to handle the measurement scale and conversion, which wouldn't work for scipy)
I read a little bit about circular statistics and agree that a separate class would be needed in view of the different concept.

As a short-term fix, one could improve the docstring to point out that `vonmises` is not a true distribution etc

(I still don´t see much added value of `vonmises`: if I understand correctly, the only advantage is that one can use arbitrary intervals of length 2 * pi to evaluate the pdf/cdf. For the cdf, the user has to fix the left endpoint manually and in my view, this is not much more convenient than mapping data point to [-pi,pi]. so I would even consider removing it from the list of continuous random variables in scipy)

> The doc is also the same for both distributions, which is confusing to a reader. But perhaps not surprising given scipy/stats/_continuous_distns.py:6156-6157

Ref to #6358 
> this is not much more convenient than mapping data point to [-pi,pi]

If I understand what you mean, then no. Using a fixed interval requires that vonmises has two shape parameters that moves the underlying periodic pdf and cdf into the [-pi, pi] or [0, 2*pi] interval. Then we can shift datapoints into the same fixed interval.
@josef-pkt I intend to update a few of the docstrings of distribution in stats and wanted to add a few sentences on `vonmises` nd `vonmises_line` as well.

> `vonmises` is a circular distribution. Currently, there is no circular distribution framework in scipy. The `cdf` is implemented such that `cdf(x + 2*np.pi) == cdf(x) + 1`.
> 
> `vonmises_line` is the same distribution, defined on :math:`[-\pi, \pi]` on the real line. This is a regular (i.e. non-circular) distribution.

Any suggestions what else one should mention? Thanks for your input.

(I don't remember the details right now for the different methods)
about vonmises: It should explain, if it doesn't already, that vonmises does not define and enforce bounds or a fixed interval for the support of the distribution. 
Users can choose an interval of length 2 pi for which vonmises can then be treated as a proper distribution (e.g. assuming we subtract cdf of lower bound.)
pdf(x) == pdf(x + 2 * pi) ?

(I don't remember how ppf is defined.) 

Resolving patch:
diff --git a/scipy/stats/_continuous_distns.py b/scipy/stats/_continuous_distns.py
--- a/scipy/stats/_continuous_distns.py
+++ b/scipy/stats/_continuous_distns.py
@@ -127,9 +127,7 @@ class norm_gen(rv_continuous):
 
         f(x) = \frac{\exp(-x^2/2)}{\sqrt{2\pi}}
 
-    The survival function, ``norm.sf``, is also referred to as the
-    Q-function in some contexts (see, e.g.,
-    `Wikipedia's <https://en.wikipedia.org/wiki/Q-function>`_ definition).
+    for a real number :math:`x`.
 
     %(after_notes)s
 
@@ -301,7 +299,7 @@ class arcsine_gen(rv_continuous):
 
         f(x) = \frac{1}{\pi \sqrt{x (1-x)}}
 
-    for :math:`0 \le x \le 1`.
+    for :math:`0 < x < 1`.
 
     %(after_notes)s
 
@@ -556,8 +554,8 @@ class betaprime_gen(rv_continuous):
 
         f(x, a, b) = \frac{x^{a-1} (1+x)^{-a-b}}{\beta(a, b)}
 
-    for :math:`x > 0`, :math:`a > 0`, :math:`b > 0`, where :math:`\beta(a, b)` is the beta
-    function (see `scipy.special.beta`).
+    for :math:`x > 0`, :math:`a > 0`, :math:`b > 0`, where
+    :math:`\beta(a, b)` is the beta function (see `scipy.special.beta`).
 
     `betaprime` takes ``a`` and ``b`` as shape parameters.
 
@@ -620,9 +618,9 @@ class bradford_gen(rv_continuous):
 
     .. math::
 
-        f(x, c) = \frac{c}{k (1+cx)}
+        f(x, c) = \frac{c}{\log(1+c) (1+cx)}
 
-    for :math:`0 < x < 1`, :math:`c > 0` and :math:`k = \log(1+c)`.
+    for :math:`0 < x < 1` and :math:`c > 0`.
 
     `bradford` takes ``c`` as a shape parameter for :math:`c`.
 
@@ -682,7 +680,7 @@ class burr_gen(rv_continuous):
 
         f(x, c, d) = c d x^{-c-1} (1+x^{-c})^{-d-1}
 
-    for :math:`x > 0`.
+    for :math:`x > 0` and :math:`c, d > 0`.
 
     `burr` takes :math:`c` and :math:`d` as shape parameters.
 
@@ -737,7 +735,7 @@ class burr12_gen(rv_continuous):
 
         f(x, c, d) = c d x^{c-1} (1+x^c)^{-d-1}
 
-    for :math:`x > 0`.
+    for :math:`x > 0` and :math:`c, d > 0`.
 
     `burr12` takes ``c`` and ``d`` as shape parameters for :math:`c`
     and :math:`d`.
@@ -810,7 +808,7 @@ class fisk_gen(burr_gen):
 
         f(x, c) = c x^{-c-1} (1 + x^{-c})^{-2}
 
-    for :math:`x > 0`.
+    for :math:`x > 0` and :math:`c > 0`.
 
     `fisk` takes ``c`` as a shape parameter for :math:`c`.
 
@@ -853,12 +851,14 @@ class cauchy_gen(rv_continuous):
 
     Notes
     -----
-    The probability density function for `cauchy` is:
+    The probability density function for `cauchy` is
 
     .. math::
 
         f(x) = \frac{1}{\pi (1 + x^2)}
 
+    for a real number :math:`x`.
+
     %(after_notes)s
 
     %(example)s
@@ -906,10 +906,11 @@ class chi_gen(rv_continuous):
 
     .. math::
 
-        f(x, df) = \frac{1}{2^{df/2-1} \Gamma \left( df/2 \right)}
-                   x^{df-1} \exp \left( -x^2/2 \right)
+        f(x, k) = \frac{1}{2^{k/2-1} \Gamma \left( k/2 \right)}
+                   x^{k-1} \exp \left( -x^2/2 \right)
 
-    for :math:`x > 0`. :math:`\Gamma` is the gamma function
+    for :math:`x > 0` and :math:`k > 0` (degrees of freedom, denoted ``df``
+    in the implementation). :math:`\Gamma` is the gamma function
     (`scipy.special.gamma`).
 
     Special cases of `chi` are:
@@ -918,7 +919,7 @@ class chi_gen(rv_continuous):
         - ``chi(2, 0, scale)`` is equivalent to `rayleigh`
         - ``chi(3, 0, scale)`` is equivalent to `maxwell`
 
-    `chi` takes ``df`` as a shape parameter for :math:`df`.
+    `chi` takes ``df`` as a shape parameter.
 
     %(after_notes)s
 
@@ -970,12 +971,13 @@ class chi2_gen(rv_continuous):
 
     .. math::
 
-        f(x, df) = \frac{1}{2^{df/2} \Gamma \left( df/2 \right)}
-                   x^{df/2-1} \exp \left( -x/2 \right)
+        f(x, k) = \frac{1}{2^{k/2} \Gamma \left( k/2 \right)}
+                   x^{k/2-1} \exp \left( -x/2 \right)
 
-    for :math:`x > 0`.
+    for :math:`x > 0`  and :math:`k > 0` (degrees of freedom, denoted ``df``
+    in the implementation).
 
-    `chi2` takes ``df`` as a shape parameter for :math:`df`.
+    `chi2` takes ``df`` as a shape parameter.
 
     %(after_notes)s
 
@@ -1066,8 +1068,8 @@ class dgamma_gen(rv_continuous):
 
         f(x, a) = \frac{1}{2\Gamma(a)} |x|^{a-1} \exp(-|x|)
 
-    for :math:`a > 0`. :math:`\Gamma` is the gamma function
-    (`scipy.special.gamma`).
+    for a real number :math:`x` and :math:`a > 0`. :math:`\Gamma` is the
+    gamma function (`scipy.special.gamma`).
 
     `dgamma` takes ``a`` as a shape parameter for :math:`a`.
 
@@ -1118,12 +1120,14 @@ class dweibull_gen(rv_continuous):
 
     Notes
     -----
-    The probability density function for `dweibull` is:
+    The probability density function for `dweibull` is given by
 
     .. math::
 
         f(x, c) = c / 2 |x|^{c-1} \exp(-|x|^c)
 
+    for a real number :math:`x` and :math:`c > 0`.
+    
     `dweibull` takes ``c`` as a shape parameter for :math:`c`.
 
     %(after_notes)s
@@ -1287,15 +1291,14 @@ class exponnorm_gen(rv_continuous):
 
     .. math::
 
-        f(x, K) = \frac{1}{2K} \exp\left(\frac{1}{2 K^2}\right) \exp(-x / K)
+        f(x, K) = \frac{1}{2K} \exp\left(\frac{1}{2 K^2} - x / K \right)
                   \text{erfc}\left(-\frac{x - 1/K}{\sqrt{2}}\right)
 
-    where the shape parameter :math:`K > 0`.
+    where :math:`x` is a real number and :math:`K > 0`.
 
-    It can be thought of as the sum of a normally distributed random
-    value with mean ``loc`` and sigma ``scale`` and an exponentially
-    distributed random number with a pdf proportional to ``exp(-lambda * x)``
-    where ``lambda = (K * scale)**(-1)``.
+    It can be thought of as the sum of a standard normal random variable
+    and an independent exponentially distributed random variable with rate
+    ``1/K``.
 
     %(after_notes)s
 
@@ -1462,9 +1465,9 @@ class fatiguelife_gen(rv_continuous):
 
     .. math::
 
-        f(x, c) = \frac{x+1}{ 2c\sqrt{2\pi x^3} \exp(-\frac{(x-1)^2}{2x c^2})}
+        f(x, c) = \frac{x+1}{2c\sqrt{2\pi x^3}} \exp(-\frac{(x-1)^2}{2x c^2})
 
-    for :math:`x > 0`.
+    for :math:`x > 0` and :math:`c > 0`.
 
     `fatiguelife` takes ``c`` as a shape parameter for :math:`c`.
 
@@ -2112,13 +2115,13 @@ class genpareto_gen(rv_continuous):
 
     .. math::
 
-        f(x, c=0) = \exp(-x)
+        f(x, 0) = \exp(-x)
 
     For :math:`c=-1`, `genpareto` is uniform on ``[0, 1]``:
 
     .. math::
 
-        f(x, c=-1) = x
+        f(x, -1) = 1
 
     %(after_notes)s
 
@@ -2924,7 +2927,8 @@ class halflogistic_gen(rv_continuous):
 
     .. math::
 
-        f(x) = \frac{ 2 e^{-x} }{ (1+e^{-x})^2 } = \frac{1}{2} sech(x/2)^2
+        f(x) = \frac{ 2 e^{-x} }{ (1+e^{-x})^2 }
+             = \frac{1}{2} \text{sech}(x/2)^2
 
     for :math:`x \ge 0`.
 
@@ -2976,7 +2980,7 @@ class halfnorm_gen(rv_continuous):
 
     .. math::
 
-        f(x) = \sqrt{2/\pi} e^{-\frac{x^2}{2}}
+        f(x) = \sqrt{2/\pi} \exp(-x^2 / 2)
 
     for :math:`x > 0`.
 
@@ -3027,7 +3031,9 @@ class hypsecant_gen(rv_continuous):
 
     .. math::
 
-        f(x) = \frac{1}{\pi} sech(x)
+        f(x) = \frac{1}{\pi} \text{sech}(x)
+
+    for a real number :math:`x`.
 
     %(after_notes)s
 
@@ -3068,7 +3074,9 @@ class gausshyper_gen(rv_continuous):
         f(x, a, b, c, z) = C x^{a-1} (1-x)^{b-1} (1+zx)^{-c}
 
     for :math:`0 \le x \le 1`, :math:`a > 0`, :math:`b > 0`, and
-    :math:`C = \frac{1}{B(a, b) F[2, 1](c, a; a+b; -z)}`
+    :math:`C = \frac{1}{B(a, b) F[2, 1](c, a; a+b; -z)}`.
+    :math:`F[2, 1]` is the Gauss hypergeometric function
+    `scipy.special.hyp2f1`.
 
     `gausshyper` takes :math:`a`, :math:`b`, :math:`c` and :math:`z` as shape
     parameters.
@@ -3181,7 +3189,7 @@ class invgauss_gen(rv_continuous):
         f(x, \mu) = \frac{1}{\sqrt{2 \pi x^3}}
                     \exp(-\frac{(x-\mu)^2}{2 x \mu^2})
 
-    for :math:`x > 0`.
+    for :math:`x > 0` and :math:`\mu > 0`.
 
     `invgauss` takes ``mu`` as a shape parameter for :math:`\mu`.
 
@@ -3232,7 +3240,7 @@ class norminvgauss_gen(rv_continuous):
 
     .. math::
 
-        f(x; a, b) = (a \exp(\sqrt{a^2 - b^2} + b x)) /
+        f(x, a, b) = (a \exp(\sqrt{a^2 - b^2} + b x)) /
                      (\pi \sqrt{1 + x^2} \, K_1(a \sqrt{1 + x^2}))
 
     where `x` is a real number, the parameter `a` is the tail heaviness
@@ -3449,12 +3457,14 @@ class laplace_gen(rv_continuous):
 
     Notes
     -----
-    The probability density function for `laplace` is:
+    The probability density function for `laplace` is
 
     .. math::
 
         f(x) = \frac{1}{2} \exp(-|x|)
 
+    for a real number :math:`x`.
+
     %(after_notes)s
 
     %(example)s
@@ -3498,7 +3508,7 @@ class levy_gen(rv_continuous):
 
     .. math::
 
-        f(x) = \frac{1}{x \sqrt{2\pi x}} \exp{\left(-\frac{1}{2x} \right)}
+        f(x) = \frac{1}{\sqrt{2\pi x^3}} \exp\left(-\frac{1}{2x}\right)
 
     for :math:`x > 0`.
 
@@ -3594,61 +3604,62 @@ class levy_stable_gen(rv_continuous):
     The distribution for `levy_stable` has characteristic function:
 
     .. math::
-            
-        \varphi(t; \alpha, \beta, c, \mu) = e^{ it\mu -|ct|^{\alpha }(1-i\beta \operatorname{sign}(t)\Phi(\alpha ,t )) }
+
+        \varphi(t, \alpha, \beta, c, \mu) =
+        e^{it\mu -|ct|^{\alpha}(1-i\beta \operatorname{sign}(t)\Phi(\alpha, t))}
 
     where:
-              
+
     .. math::
-        
+
         \Phi = \begin{cases}
                 \tan \left({\frac {\pi \alpha }{2}}\right)&\alpha \neq 1\\
                 -{\frac {2}{\pi }}\log |t|&\alpha =1
                 \end{cases}
-           
+
     The probability density function for `levy_stable` is:
-        
+
     .. math::
-    
+
         f(x) = \frac{1}{2\pi}\int_{-\infty}^\infty \varphi(t)e^{-ixt}\,dt
-        
+
     where :math:`-\infty < t < \infty`. This integral does not have a known closed form.
-    
+
     For evaluation of pdf we use either Zolotarev :math:`S_0` parameterization with integration, 
     direct integration of standard parameterization of characteristic function or FFT of 
     characteristic function. If set to other than None and if number of points is greater than 
     ``levy_stable.pdf_fft_min_points_threshold`` (defaults to None) we use FFT otherwise we use one 
     of the other methods. 
-    
+
     The default method is 'best' which uses Zolotarev's method if alpha = 1 and integration of
     characteristic function otherwise. The default method can be changed by setting 
     ``levy_stable.pdf_default_method`` to either 'zolotarev', 'quadrature' or 'best'. 
-    
+
     To increase accuracy of FFT calculation one can specify ``levy_stable.pdf_fft_grid_spacing`` 
     (defaults to 0.001) and ``pdf_fft_n_points_two_power`` (defaults to a value that covers the 
     input range * 4). Setting ``pdf_fft_n_points_two_power`` to 16 should be sufficiently accurate 
     in most cases at the expense of CPU time.
-    
+
     For evaluation of cdf we use Zolatarev :math:`S_0` parameterization with integration or integral of
     the pdf FFT interpolated spline. The settings affecting FFT calculation are the same as
     for pdf calculation. Setting the threshold to ``None`` (default) will disable FFT. For cdf 
     calculations the Zolatarev method is superior in accuracy, so FFT is disabled by default.
-    
+
     Fitting estimate uses quantile estimation method in [MC]. MLE estimation of parameters in
     fit method uses this quantile estimate initially. Note that MLE doesn't always converge if 
     using FFT for pdf calculations; so it's best that ``pdf_fft_min_points_threshold`` is left unset. 
     
     .. warning::
-    
+
         For pdf calculations implementation of Zolatarev is unstable for values where alpha = 1 and 
         beta != 0. In this case the quadrature method is recommended. FFT calculation is also 
         considered experimental.
-        
+
         For cdf calculations FFT calculation is considered experimental. Use Zolatarev's method 
         instead (default).
 
     %(after_notes)s
-    
+
     References
     ----------    
     .. [MC] McCulloch, J., 1986. Simple consistent estimators of stable distribution parameters.
@@ -4229,7 +4240,7 @@ class lognorm_gen(rv_continuous):
     .. math::
 
         f(x, s) = \frac{1}{s x \sqrt{2\pi}}
-                  \exp(-\frac{1}{2} (\frac{\log(x)}{s})^2)
+                  \exp(-\frac{\log^2(x}{2s^2})
 
     for :math:`x > 0`, :math:`s > 0`.
 
@@ -4470,7 +4481,7 @@ class mielke_gen(rv_continuous):
 
         f(x, k, s) = \frac{k x^{k-1}}{(1+x^s)^{1+k/s}}
 
-    for :math:`x > 0`.
+    for :math:`x > 0` and :math:`k, s > 0`.
 
     `mielke` takes ``k`` and ``s`` as shape parameters.
 
@@ -4754,16 +4765,13 @@ class kappa3_gen(rv_continuous):
 
     Notes
     -----
-    The probability density function for `kappa` is:
+    The probability density function for `kappa3` is:
 
     .. math::
 
-        f(x, a) = \begin{cases}
-                    a [a + x^a]^{-(a + 1)/a},     &\text{for } x > 0\\
-                    0.0,                          &\text{for } x \le 0
-                  \end{cases}
+        f(x, a) = a (a + x^a)^{-(a + 1)/a}
 
-    for :math:`a > 0`.
+    for :math:`x > 0` and :math:`a > 0`.
 
     `kappa3` takes ``a`` as a shape parameter for :math:`a`.
 
@@ -4787,9 +4795,7 @@ def _argcheck(self, a):
         return a > 0
 
     def _pdf(self, x, a):
-        # kappa3.pdf(x, a) =
-        #     a*[a + x**a]**(-(a + 1)/a),     for x > 0
-        #     0.0,                            for x <= 0
+        # kappa3.pdf(x, a) = a*(a + x**a)**(-(a + 1)/a),     for x > 0
         return a*(a + x**a)**(-1.0/a-1)
 
     def _cdf(self, x, a):
@@ -4818,6 +4824,8 @@ class moyal_gen(rv_continuous):
 
         f(x) = \exp(-(x + \exp(-x))/2) / \sqrt{2\pi}
 
+    for a real number :math:`x`.
+
     %(after_notes)s
 
     This distribution has utility in high-energy physics and radiation
@@ -4951,10 +4959,14 @@ class ncx2_gen(rv_continuous):
 
     .. math::
 
-        f(x, df, nc) = \exp(-\frac{nc+x}{2}) \frac{1}{2} (x/nc)^{(df-2)/4}
-                       I[(df-2)/2](\sqrt{nc x})
+        f(x, k, \lambda) = \frac{1}{2} \exp(-(\lambda+x)/2)
+            (x/\lambda)^{(k-2)/4}  I_{(k-2)/2}(\sqrt{\lambda x})
 
-    for :math:`x > 0`.
+    for :math:`x > 0` and :math:`k, \lambda > 0`. :math:`k` specifies the
+    degrees of freedom (denoted ``df`` in the implementation) and
+    :math:`\lambda` is the non-centrality parameter (denoted ``nc`` in the
+    implementation). :math:`I_\nu` denotes the modified Bessel function of
+    first order of degree :math:`\nu` (`scipy.special.iv`).
 
     `ncx2` takes ``df`` and ``nc`` as shape parameters.
 
@@ -5080,7 +5092,7 @@ class t_gen(rv_continuous):
 
     .. math::
 
-        f(x; \nu) = \frac{\Gamma((\nu+1)/2)}
+        f(x, \nu) = \frac{\Gamma((\nu+1)/2)}
                         {\sqrt{\pi \nu} \Gamma(\nu)}
                     (1+x^2/\nu)^{-(\nu+1)/2}
 
@@ -5151,17 +5163,18 @@ class nct_gen(rv_continuous):
 
     Notes
     -----
-    The probability density function for `nct` is:
+    If :math:`Y` is a standard normal random variable and :math:`V` is
+    an independent chi-square random variable (`chi2`) with :math:`k` degrees
+    of freedom, then
 
     .. math::
 
-        f(x, df, nc) = \frac{df^{df/2} \Gamma(df+1)}{2^{df}
-                       \exp(nc^2 / 2) (df+x^2)^{df/2} \Gamma(df/2)}
+        X = \frac{Y + c}{\sqrt{V/k}}
 
-    for :math:`df > 0`.
-
-    `nct` takes ``df`` and ``nc`` as shape parameters. :math:`\Gamma` is the 
-    gamma function (`scipy.special.gamma`).
+    has a non-central Student's t distribution on the real line.
+    The degrees of freedom parameter :math:`k` (denoted ``df`` in the
+    implementation) satisfies :math:`k > 0` and the noncentrality parameter
+    :math:`c` (denoted ``nct`` in the implementation) is a real number.
 
     %(after_notes)s
 
@@ -5178,10 +5191,6 @@ def _rvs(self, df, nc):
         return n * np.sqrt(df) / np.sqrt(c2)
 
     def _pdf(self, x, df, nc):
-        # nct.pdf(x, df, nc) =
-        #                               df**(df/2) * gamma(df+1)
-        #                ----------------------------------------------------
-        #                2**df*exp(nc**2/2) * (df+x**2)**(df/2) * gamma(df/2)
         n = df*1.0
         nc = nc*1.0
         x2 = x*x
@@ -5774,7 +5783,7 @@ class reciprocal_gen(rv_continuous):
 
         f(x, a, b) = \frac{1}{x \log(b/a)}
 
-    for :math:`a \le x \le b`, :math:`a, b > 0`.
+    for :math:`a \le x \le b`, :math:`b > a > 0`.
 
     `reciprocal` takes :math:`a` and :math:`b` as shape parameters.
 
@@ -5787,7 +5796,7 @@ def _argcheck(self, a, b):
         self.a = a
         self.b = b
         self.d = np.log(b*1.0 / a)
-        return (a > 0) & (b > 0) & (b > a)
+        return (a > 0) & (b > a)
 
     def _pdf(self, x, a, b):
         # reciprocal.pdf(x, a, b) = 1 / (x*log(b/a))
@@ -5823,9 +5832,10 @@ class rice_gen(rv_continuous):
 
     .. math::
 
-        f(x, b) = x \exp(- \frac{x^2 + b^2}{2}) I[0](x b)
+        f(x, b) = x \exp(- \frac{x^2 + b^2}{2}) I_0(x b)
 
-    for :math:`x > 0`, :math:`b > 0`.
+    for :math:`x > 0`, :math:`b > 0`. :math:`I_0` is the modified Bessel
+    function of order zero (`scipy.special.i0`).
 
     `rice` takes ``b`` as a shape parameter for :math:`b`.
 
@@ -5969,9 +5979,9 @@ class skew_norm_gen(rv_continuous):
 
         skewnorm.pdf(x, a) = 2 * norm.pdf(x) * norm.cdf(a*x)
 
-    `skewnorm` takes :math:`a` as a skewness parameter
-    When ``a = 0`` the distribution is identical to a normal distribution.
-    rvs implements the method of [1]_.
+    `skewnorm` takes a real number :math:`a` as a skewness parameter
+    When ``a = 0`` the distribution is identical to a normal distribution
+    (`norm`). `rvs` implements the method of [1]_.
 
     %(after_notes)s
 
@@ -6098,7 +6108,7 @@ class triang_gen(rv_continuous):
     -----
     The triangular distribution can be represented with an up-sloping line from
     ``loc`` to ``(loc + c*scale)`` and then downsloping for ``(loc + c*scale)``
-    to ``(loc+scale)``.
+    to ``(loc + scale)``.
 
     `triang` takes ``c`` as a shape parameter for :math:`c`.
 
@@ -6294,13 +6304,13 @@ class tukeylambda_gen(rv_continuous):
     A flexible distribution, able to represent and interpolate between the
     following distributions:
 
-    - Cauchy                (lam=-1)
-    - logistic              (lam=0.0)
-    - approx Normal         (lam=0.14)
-    - u-shape               (lam = 0.5)
-    - uniform from -1 to 1  (lam = 1)
+    - Cauchy                (:math:`lambda = -1`)
+    - logistic              (:math:`lambda = 0`)
+    - approx Normal         (:math:`lambda = 0.14`)
+    - uniform from -1 to 1  (:math:`lambda = 1`)
 
-    `tukeylambda` takes ``lam`` as a shape parameter.
+    `tukeylambda` takes a real number :math:`lambda` (denoted ``lam``
+    in the implementation) as a shape parameter.
 
     %(after_notes)s
 
@@ -6347,7 +6357,9 @@ def __init__(self, ptp, fscale):
 class uniform_gen(rv_continuous):
     r"""A uniform continuous random variable.
 
-    This distribution is constant between `loc` and ``loc + scale``.
+    In the standard form, the distribution is uniform on ``[0, 1]``. Using
+    the parameters ``loc`` and ``scale``, one obtains the uniform distribution
+    on ``[loc, loc + scale]``.
 
     %(before_notes)s
 
@@ -6532,25 +6544,26 @@ class vonmises_gen(rv_continuous):
 
     Notes
     -----
-    If `x` is not in range or `loc` is not in range it assumes they are angles
-    and converts them to [-\pi, \pi] equivalents.
-
-    The probability density function for `vonmises` is:
+    The probability density function for `vonmises` and `vonmises_line` is:
 
     .. math::
 
-        f(x, \kappa) = \frac{ \exp(\kappa \cos(x)) }{ 2 \pi I[0](\kappa) }
+        f(x, \kappa) = \frac{ \exp(\kappa \cos(x)) }{ 2 \pi I_0(\kappa) }
 
-    for :math:`-\pi \le x \le \pi`, :math:`\kappa > 0`.
+    for :math:`-\pi \le x \le \pi`, :math:`\kappa > 0`. :math:`I_0` is the
+    modified Bessel function of order zero (`scipy.special.i0`).
 
-    `vonmises` takes ``kappa`` as a shape parameter for :math:`\kappa`.
+    `vonmises` is a circular distribution which does not restrict the
+    distribution to a fixed interval. Currently, there is no circular
+    distribution framework in scipy. The ``cdf`` is implemented such that
+    ``cdf(x + 2*np.pi) == cdf(x) + 1``.
 
-    %(after_notes)s
+    `vonmises_line` is the same distribution, defined on :math:`[-\pi, \pi]`
+    on the real line. This is a regular (i.e. non-circular) distribution.
 
-    See Also
-    --------
-    vonmises_line : The same distribution, defined on a [-\pi, \pi] segment
-                    of the real line.
+    `vonmises` and `vonmises_line` take ``kappa`` as a shape parameter.
+
+    %(after_notes)s
 
     %(example)s
 
@@ -6700,7 +6713,7 @@ class gennorm_gen(rv_continuous):
     `gennorm` takes ``beta`` as a shape parameter for :math:`\beta`.
     For :math:`\beta = 1`, it is identical to a Laplace distribution.
     For :math:`\beta = 2`, it is identical to a normal distribution
-    (with :math:`scale=1/\sqrt{2}`).
+    (with ``scale=1/sqrt(2)``).
 
     See Also
     --------
@@ -6763,12 +6776,13 @@ class halfgennorm_gen(rv_continuous):
 
         f(x, \beta) = \frac{\beta}{\Gamma(1/\beta)} \exp(-|x|^\beta)
 
-    :math:`\Gamma` is the gamma function (`scipy.special.gamma`).
+    for :math:`x > 0`. :math:`\Gamma` is the gamma function
+    (`scipy.special.gamma`).
 
     `gennorm` takes ``beta`` as a shape parameter for :math:`\beta`.
     For :math:`\beta = 1`, it is identical to an exponential distribution.
     For :math:`\beta = 2`, it is identical to a half normal distribution
-    (with :math:`scale=1/\sqrt{2}`).
+    (with ``scale=1/sqrt(2)``).
 
     See Also
     --------
@@ -6831,12 +6845,12 @@ class crystalball_gen(rv_continuous):
                             N A (B - x)^{-m}  &\text{for } x \le -\beta
                           \end{cases}
 
-    where :math:`A = (m / |beta|)**n * exp(-beta**2 / 2)`,
-    :math:`B = m/|beta| - |beta|` and :math:`N` is a normalisation constant.
+    where :math:`A = (m / |\beta|)^n  \exp(-\beta^2 / 2)`,
+    :math:`B = m/|\beta| - |\beta|` and :math:`N` is a normalisation constant.
 
     `crystalball` takes :math:`\beta` and :math:`m` as shape parameters.
     :math:`\beta` defines the point where the pdf changes from a power-law to a
-    gaussian distribution :math:`m` is power of the power-law tail.
+    Gaussian distribution :math:`m` is power of the power-law tail.
 
     References
     ----------
@@ -6934,7 +6948,7 @@ class argus_gen(rv_continuous):
         f(x, \chi) = \frac{\chi^3}{\sqrt{2\pi} \Psi(\chi)} x \sqrt{1-x^2}
                      \exp(-\chi^2 (1 - x^2)/2)
 
-    for 0 < x < 1, where
+    for :math:`0 < x < 1`, where
 
     .. math::
 


Test patch: