Skip to content

Commit 9630cc5

Browse files
authored
Merge pull request #717 from HugoMVale/stats-distribution-exponential
Extension of PR#679 to `stdlib_stats_distribution_exponential`
2 parents 7cdecb5 + afc1844 commit 9630cc5

File tree

4 files changed

+152
-94
lines changed

4 files changed

+152
-94
lines changed

doc/specs/stdlib_stats_distribution_exponential.md

+26-21
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,37 @@ Experimental
1414

1515
### Description
1616

17-
An exponential distribution is the distribution of time between events in a Poisson point process. The inverse scale parameter `lambda` specifies the average time between events, also called the rate of events.
17+
An exponential distribution is the distribution of time between events in a Poisson point process. The inverse scale parameter `lambda` specifies the average time between events ($\lambda$), also called the rate of events.
1818

19-
Without argument the function returns a random sample from the standard exponential distribution `E(1)` with `lambda = 1`.
19+
Without argument, the function returns a random sample from the standard exponential distribution $E(\lambda=1)$.
2020

21-
With a single argument, the function returns a random sample from the exponential distribution `E(lambda)`.
21+
With a single argument, the function returns a random sample from the exponential distribution $E(\lambda=\text{lambda})$.
2222
For complex arguments, the real and imaginary parts are sampled independently of each other.
2323

24-
With two arguments the function returns a rank one array of exponentially distributed random variates.
24+
With two arguments, the function returns a rank-1 array of exponentially distributed random variates.
2525

26-
Note: the algorithm used for generating exponetial random variates is fundamentally limited to double precision. Ref.: Marsaglia, G. & Tsang, W.W. (2000) `The ziggurat method for generating random variables', J. Statist. Software, v5(8).
26+
@note
27+
The algorithm used for generating exponential random variates is fundamentally limited to double precision.[^1]
2728

2829
### Syntax
2930

3031
`result = [[stdlib_stats_distribution_exponential(module):rvs_exp(interface)]]([lambda] [[, array_size]])`
3132

3233
### Class
3334

34-
Function
35+
Elemental function
3536

3637
### Arguments
3738

38-
`lambda`: optional argument has `intent(in)` and is a scalar of type `real` or `complex`. The value of `lambda` has to be non-negative.
39+
`lambda`: optional argument has `intent(in)` and is a scalar of type `real` or `complex`.
40+
If `lambda` is `real`, its value must be positive. If `lambda` is `complex`, both the real and imaginary components must be positive.
3941

4042
`array_size`: optional argument has `intent(in)` and is a scalar of type `integer` with default kind.
4143

4244
### Return value
4345

44-
The result is a scalar or rank one array with a size of `array_size`, and has the same type of `lambda`.
46+
The result is a scalar or rank-1 array with a size of `array_size`, and the same type as `lambda`.
47+
If `lambda` is non-positive, the result is `NaN`.
4548

4649
### Example
4750

@@ -57,15 +60,13 @@ Experimental
5760

5861
### Description
5962

60-
The probability density function (pdf) of the single real variable exponential distribution:
63+
The probability density function (pdf) of the single real variable exponential distribution is:
6164

62-
$$f(x)=\begin{cases} \lambda e^{-\lambda x} &x\geqslant 0 \\\\ 0 &x< 0\end{}$$
65+
$$f(x)=\begin{cases} \lambda e^{-\lambda x} &x\geqslant 0 \\\\ 0 &x< 0\end{cases}$$
6366

64-
For a complex variable (x + y i) with independent real x and imaginary y parts, the joint probability density function
65-
is the product of the corresponding marginal pdf of real and imaginary pdf (for more details, see
66-
"Probability and Random Processes with Applications to Signal Processing and Communications", 2nd ed., Scott L. Miller and Donald Childers, 2012, p.197):
67+
For a complex variable $z=(x + y i)$ with independent real $x$ and imaginary $y$ parts, the joint probability density function is the product of the corresponding real and imaginary marginal pdfs:[^2]
6768

68-
$$f(x+\mathit{i}y)=f(x)f(y)=\begin{cases} \lambda_{x} \lambda_{y} e^{-(\lambda_{x} x + \lambda_{y} y)} &x\geqslant 0, y\geqslant 0 \\\\ 0 &otherwise\end{}$$
69+
$$f(x+\mathit{i}y)=f(x)f(y)=\begin{cases} \lambda_{x} \lambda_{y} e^{-(\lambda_{x} x + \lambda_{y} y)} &x\geqslant 0, y\geqslant 0 \\\\ 0 &\text{otherwise}\end{cases}$$
6970

7071
### Syntax
7172

@@ -80,12 +81,13 @@ Elemental function
8081
`x`: has `intent(in)` and is a scalar of type `real` or `complex`.
8182

8283
`lambda`: has `intent(in)` and is a scalar of type `real` or `complex`.
84+
If `lambda` is `real`, its value must be positive. If `lambda` is `complex`, both the real and imaginary components must be positive.
8385

8486
All arguments must have the same type.
8587

8688
### Return value
8789

88-
The result is a scalar or an array, with a shape conformable to arguments, and has the same type of input arguments.
90+
The result is a scalar or an array, with a shape conformable to the arguments, and the same type as the input arguments. If `lambda` is non-positive, the result is `NaN`.
8991

9092
### Example
9193

@@ -103,13 +105,11 @@ Experimental
103105

104106
Cumulative distribution function (cdf) of the single real variable exponential distribution:
105107

106-
$$F(x)=\begin{cases}1 - e^{-\lambda x} &x\geqslant 0 \\\\ 0 &x< 0\end{}$$
108+
$$F(x)=\begin{cases}1 - e^{-\lambda x} &x\geqslant 0 \\\\ 0 &x< 0\end{cases}$$
107109

108-
For a complex variable (x + y i) with independent real x and imaginary y parts, the joint cumulative distribution
109-
function is the product of corresponding marginal cdf of real and imaginary cdf (for more details, see
110-
"Probability and Random Processes with Applications to Signal Processing and Communications", 2nd ed., Scott L. Miller and Donald Childers, 2012, p.197):
110+
For a complex variable $z=(x + y i)$ with independent real $x$ and imaginary $y$ parts, the joint cumulative distribution function is the product of corresponding real and imaginary marginal cdfs:[^2]
111111

112-
$$F(x+\mathit{i}y)=F(x)F(y)=\begin{cases} (1 - e^{-\lambda_{x} x})(1 - e^{-\lambda_{y} y}) &x\geqslant 0, \;\; y\geqslant 0 \\\\ 0 &otherwise \end{}$$
112+
$$F(x+\mathit{i}y)=F(x)F(y)=\begin{cases} (1 - e^{-\lambda_{x} x})(1 - e^{-\lambda_{y} y}) &x\geqslant 0, \;\; y\geqslant 0 \\\\ 0 & \text{otherwise} \end{cases}$$
113113

114114
### Syntax
115115

@@ -124,15 +124,20 @@ Elemental function
124124
`x`: has `intent(in)` and is a scalar of type `real` or `complex`.
125125

126126
`lambda`: has `intent(in)` and is a scalar of type `real` or `complex`.
127+
If `lambda` is `real`, its value must be positive. If `lambda` is `complex`, both the real and imaginary components must be positive.
127128

128129
All arguments must have the same type.
129130

130131
### Return value
131132

132-
The result is a scalar or an array, with a shape conformable to arguments, and has the same type of input arguments.
133+
The result is a scalar or an array, with a shape conformable to the arguments, and the same type as the input arguments. If `lambda` is non-positive, the result is `NaN`.
133134

134135
### Example
135136

136137
```fortran
137138
{!example/stats_distribution_exponential/example_exponential_cdf.f90!}
138139
```
140+
141+
[^1] Marsaglia, George, and Wai Wan Tsang. "The ziggurat method for generating random variables." _Journal of statistical software_ 5 (2000): 1-7.
142+
143+
[^2] Miller, Scott, and Donald Childers. _Probability and random processes: With applications to signal processing and communications_. Academic Press, 2012 (p. 197).

example/stats_distribution_exponential/example_exponential_cdf.f90

+41-18
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,61 @@ program example_exponential_cdf
44
rexp => rvs_exp
55

66
implicit none
7-
real :: x(2, 3, 4), a(2, 3, 4)
7+
real, dimension(2, 3, 4) :: x, lambda
8+
real :: xsum
89
complex :: scale
9-
integer :: seed_put, seed_get
10+
integer :: seed_put, seed_get, i
1011

1112
seed_put = 1234567
1213
call random_seed(seed_put, seed_get)
1314

14-
print *, exp_cdf(1.0, 1.0) ! a standard exponential cumulative at 1.0
15+
! standard exponential cumulative distribution at x=1.0
16+
print *, exp_cdf(1.0, 1.0)
17+
! 0.632120550
1518

16-
! 0.632120550
19+
! cumulative distribution at x=2.0 with lambda=2
20+
print *, exp_cdf(2.0, 2.0)
21+
! 0.981684387
1722

18-
print *, exp_cdf(2.0, 2.0) ! a cumulative at 2.0 with lambda=2
19-
20-
! 0.981684387
23+
! cumulative distribution at x=2.0 with lambda=-1.0 (out of range)
24+
print *, exp_cdf(2.0, -1.0)
25+
! NaN
2126

27+
! standard exponential random variates array
2228
x = reshape(rexp(0.5, 24), [2, 3, 4])
23-
! standard exponential random variates array
24-
a(:, :, :) = 0.5
25-
print *, exp_cdf(x, a) ! a rank 3 array of standard exponential cumulative
2629

27-
! 8.57694745E-02 9.70223546E-02 1.52170658E-02 2.95336246E-02
28-
! 0.107568979 0.196659625 2.97447443E-02 0.366151094 0.163051903
29-
! 3.36527228E-02 0.385267735 0.428375721 0.103964329 0.147119939
30-
! 0.192206264 0.330693483 0.179247737 2.92580128E-02 0.332765043
31-
! 0.472417951 0.500440359 8.56802464E-02 8.72612000E-03 3.55126858E-02
30+
! a rank-3 exponential cumulative distribution
31+
lambda(:, :, :) = 0.5
32+
print *, exp_cdf(x, lambda)
33+
! 0.301409245 0.335173965 5.94930053E-02 0.113003314
34+
! 0.365694344 0.583515942 0.113774836 0.838585377
35+
! 0.509324908 0.127967060 0.857194781 0.893231630
36+
! 0.355383813 0.470882893 0.574203610 0.799321830
37+
! 0.546216846 0.111995399 0.801794767 0.922525287
38+
! 0.937719882 0.301136374 3.44503522E-02 0.134661376
39+
40+
! cumulative distribution array where lambda<=0.0 for certain elements
41+
print *, exp_cdf([1.0, 1.0, 1.0], [1.0, 0.0, -1.0])
42+
! 0.632120550 NaN NaN
43+
44+
! `cdf_exp` is pure and, thus, can be called concurrently
45+
xsum = 0.0
46+
do concurrent (i=1:size(x,3))
47+
xsum = xsum + sum(exp_cdf(x(:,:,i), lambda(:,:,i)))
48+
end do
49+
print *, xsum
50+
! 11.0886612
3251

52+
! complex exponential cumulative distribution at (0.5,0.5) with real part of
53+
! lambda=0.5 and imaginary part of lambda=1.0
3354
scale = (0.5, 1.0)
3455
print *, exp_cdf((0.5, 0.5), scale)
35-
!complex exponential cumulative distribution at (0.5,0.5) with real part of
36-
!lambda=0.5 and imaginary part of lambda=1.0
56+
! 8.70351046E-02
3757

38-
! 8.70351046E-02
58+
! As above, but with lambda%im < 0
59+
scale = (1.0, -2.0)
60+
print *, exp_cdf((1.5, 1.0), scale)
61+
! NaN
3962

4063
end program example_exponential_cdf
4164

Original file line numberDiff line numberDiff line change
@@ -1,39 +1,62 @@
11
program example_exponential_pdf
22
use stdlib_random, only: random_seed
33
use stdlib_stats_distribution_exponential, only: exp_pdf => pdf_exp, &
4-
rexp => rvs_exp
4+
rexp => rvs_exp
55

66
implicit none
7-
real :: x(2, 3, 4), a(2, 3, 4)
7+
real, dimension(2, 3, 4) :: x, lambda
8+
real :: xsum
89
complex :: scale
9-
integer :: seed_put, seed_get
10+
integer :: seed_put, seed_get, i
1011

1112
seed_put = 1234567
1213
call random_seed(seed_put, seed_get)
1314

14-
print *, exp_pdf(1.0, 1.0) !a probability density at 1.0 in standard expon
15-
16-
! 0.367879450
17-
18-
print *, exp_pdf(2.0, 2.0) !a probability density at 2.0 with lambda=2.0
19-
20-
! 3.66312787E-02
21-
22-
x = reshape(rexp(0.5, 24), [2, 3, 4]) ! standard expon random variates array
23-
a(:, :, :) = 0.5
24-
print *, exp_pdf(x, a) ! a rank 3 standard expon probability density
25-
26-
! 0.457115263 0.451488823 0.492391467 0.485233188 0.446215510
27-
! 0.401670188 0.485127628 0.316924453 0.418474048 0.483173639
28-
! 0.307366133 0.285812140 0.448017836 0.426440030 0.403896868
29-
! 0.334653258 0.410376132 0.485370994 0.333617479 0.263791025
30-
! 0.249779820 0.457159877 0.495636940 0.482243657
31-
15+
! probability density at x=1.0 in standard exponential
16+
print *, exp_pdf(1.0, 1.0)
17+
! 0.367879450
18+
19+
! probability density at x=2.0 with lambda=2.0
20+
print *, exp_pdf(2.0, 2.0)
21+
! 3.66312787E-02
22+
23+
! probability density at x=2.0 with lambda=-1.0 (out of range)
24+
print *, exp_pdf(2.0, -1.0)
25+
! NaN
26+
27+
! standard exponential random variates array
28+
x = reshape(rexp(0.5, 24), [2, 3, 4])
29+
30+
! a rank-3 exponential probability density
31+
lambda(:, :, :) = 0.5
32+
print *, exp_pdf(x, lambda)
33+
! 0.349295378 0.332413018 0.470253497 0.443498343 0.317152828
34+
! 0.208242029 0.443112582 8.07073265E-02 0.245337561 0.436016470
35+
! 7.14025944E-02 5.33841923E-02 0.322308093 0.264558554 0.212898195
36+
! 0.100339092 0.226891592 0.444002301 9.91026312E-02 3.87373678E-02
37+
! 3.11400592E-02 0.349431813 0.482774824 0.432669312
38+
39+
! probability density array where lambda<=0.0 for certain elements
40+
print *, exp_pdf([1.0, 1.0, 1.0], [1.0, 0.0, -1.0])
41+
! 0.367879450 NaN NaN
42+
43+
! `pdf_exp` is pure and, thus, can be called concurrently
44+
xsum = 0.0
45+
do concurrent (i=1:size(x,3))
46+
xsum = xsum + sum(exp_pdf(x(:,:,i), lambda(:,:,i)))
47+
end do
48+
print *, xsum
49+
! 6.45566940
50+
51+
! complex exponential probability density function at (1.5,1.0) with real part
52+
! of lambda=1.0 and imaginary part of lambda=2.0
3253
scale = (1.0, 2.)
3354
print *, exp_pdf((1.5, 1.0), scale)
34-
! a complex expon probability density function at (1.5,1.0) with real part
35-
!of lambda=1.0 and imaginary part of lambda=2.0
55+
! 6.03947677E-02
3656

37-
! 6.03947677E-02
57+
! As above, but with lambda%re < 0
58+
scale = (-1.0, 2.)
59+
print *, exp_pdf((1.5, 1.0), scale)
60+
! NaN
3861

3962
end program example_exponential_pdf

0 commit comments

Comments
 (0)