Skip to content

Commit 5644af6

Browse files
committed
Remove eltype definitions, add deprecation warning, and update documentation
1 parent 17154a2 commit 5644af6

25 files changed

+48
-96
lines changed

docs/src/extends.md

+35-44
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@ Whereas this package already provides a large collection of common distributions
44

55
Generally, you don't have to implement every API method listed in the documentation. This package provides a series of generic functions that turn a small number of internal methods into user-end API methods. What you need to do is to implement this small set of internal methods for your distributions.
66

7-
By default, `Discrete` sampleables have the support of type `Int` while `Continuous` sampleables have the support of type `Float64`. If this assumption does not hold for your new distribution or sampler, or its `ValueSupport` is neither `Discrete` nor `Continuous`, you should implement the `eltype` method in addition to the other methods listed below.
8-
97
**Note:** The methods that need to be implemented are different for distributions of different variate forms.
108

11-
129
## Create a Sampler
1310

1411
Unlike full-fledged distributions, a sampler, in general, only provides limited functionalities, mainly to support sampling.
@@ -18,60 +15,48 @@ Unlike full-fledged distributions, a sampler, in general, only provides limited
1815
To implement a univariate sampler, one can define a subtype (say `Spl`) of `Sampleable{Univariate,S}` (where `S` can be `Discrete` or `Continuous`), and provide a `rand` method, as
1916

2017
```julia
21-
function rand(rng::AbstractRNG, s::Spl)
18+
function Base.rand(rng::AbstractRNG, s::Spl)
2219
# ... generate a single sample from s
2320
end
2421
```
2522

26-
The package already implements a vectorized version of `rand!` and `rand` that repeatedly calls the scalar version to generate multiple samples; as wells as a one arg version that uses the default random number generator.
27-
28-
### Multivariate Sampler
23+
The package already implements vectorized versions `rand!(rng::AbstractRNG, s::Spl, dims::Int...)` and `rand(rng::AbstractRNG, s::Spl, dims::Int...)` that repeatedly call the scalar version to generate multiple samples.
24+
Additionally, the package implements versions of these functions without the `rng::AbstractRNG` argument that use the default random number generator.
2925

30-
To implement a multivariate sampler, one can define a subtype of `Sampleable{Multivariate,S}`, and provide both `length` and `_rand!` methods, as
26+
If there is a more efficient method to generate multiple samples, one should provide the following method
3127

3228
```julia
33-
Base.length(s::Spl) = ... # return the length of each sample
34-
35-
function _rand!(rng::AbstractRNG, s::Spl, x::AbstractVector{T}) where T<:Real
36-
# ... generate a single vector sample to x
29+
function Random.rand!(rng::AbstractRNG, s::Spl, x::AbstractArray{<:Real})
30+
# ... generate multiple samples from s in x
3731
end
3832
```
3933

40-
This function can assume that the dimension of `x` is correct, and doesn't need to perform dimension checking.
34+
### Multivariate Sampler
4135

42-
The package implements both `rand` and `rand!` as follows (which you don't need to implement in general):
36+
To implement a multivariate sampler, one can define a subtype of `Sampleable{Multivariate,S}`, and provide `length`, `rand`, and `rand!` methods, as
4337

4438
```julia
45-
function _rand!(rng::AbstractRNG, s::Sampleable{Multivariate}, A::DenseMatrix)
46-
for i = 1:size(A,2)
47-
_rand!(rng, s, view(A,:,i))
48-
end
49-
return A
50-
end
39+
Base.length(s::Spl) = ... # return the length of each sample
5140

52-
function rand!(rng::AbstractRNG, s::Sampleable{Multivariate}, A::AbstractVector)
53-
length(A) == length(s) ||
54-
throw(DimensionMismatch("Output size inconsistent with sample length."))
55-
_rand!(rng, s, A)
41+
function Base.rand(rng::AbstractRNG, s::Spl)
42+
# ... generate a single vector sample from s
5643
end
5744

58-
function rand!(rng::AbstractRNG, s::Sampleable{Multivariate}, A::DenseMatrix)
59-
size(A,1) == length(s) ||
60-
throw(DimensionMismatch("Output size inconsistent with sample length."))
61-
_rand!(rng, s, A)
45+
@inline function Random.rand!(rng::AbstractRNG, s::Spl, x::AbstractVector{<:Real})
46+
# `@inline` + `@boundscheck` allows users to skip bound checks by calling `@inbounds rand!(...)`
47+
# Ref https://docs.julialang.org/en/v1/devdocs/boundscheck/#Eliding-bounds-checks
48+
@boundscheck # ... check size (and possibly indices) of `x`
49+
# ... generate a single vector sample from s in x
6250
end
63-
64-
rand(rng::AbstractRNG, s::Sampleable{Multivariate,S}) where {S<:ValueSupport} =
65-
_rand!(rng, s, Vector{eltype(S)}(length(s)))
66-
67-
rand(rng::AbstractRNG, s::Sampleable{Multivariate,S}, n::Int) where {S<:ValueSupport} =
68-
_rand!(rng, s, Matrix{eltype(S)}(length(s), n))
6951
```
7052

7153
If there is a more efficient method to generate multiple vector samples in a batch, one should provide the following method
7254

7355
```julia
74-
function _rand!(rng::AbstractRNG, s::Spl, A::DenseMatrix{T}) where T<:Real
56+
@inline function Random.rand!(rng::AbstractRNG, s::Spl, A::AbstractMatrix{<:Real})
57+
# `@inline` + `@boundscheck` allows users to skip bound checks by calling `@inbounds rand!(...)`
58+
# Ref https://docs.julialang.org/en/v1/devdocs/boundscheck/#Eliding-bounds-checks
59+
@boundscheck # ... check size (and possibly indices) of `x`
7560
# ... generate multiple vector samples in batch
7661
end
7762
```
@@ -80,17 +65,22 @@ Remember that each *column* of A is a sample.
8065

8166
### Matrix-variate Sampler
8267

83-
To implement a multivariate sampler, one can define a subtype of `Sampleable{Multivariate,S}`, and provide both `size` and `_rand!` methods, as
68+
To implement a multivariate sampler, one can define a subtype of `Sampleable{Multivariate,S}`, and provide `size`, `rand`, and `rand!` methods, as
8469

8570
```julia
8671
Base.size(s::Spl) = ... # the size of each matrix sample
8772

88-
function _rand!(rng::AbstractRNG, s::Spl, x::DenseMatrix{T}) where T<:Real
89-
# ... generate a single matrix sample to x
73+
function Base.rand(rng::AbstractRNG, s::Spl)
74+
# ... generate a single matrix sample from s
9075
end
91-
```
9276

93-
Note that you can assume `x` has correct dimensions in `_rand!` and don't have to perform dimension checking, the generic `rand` and `rand!` will do dimension checking and array allocation for you.
77+
@inline function Random.rand!(rng::AbstractRNG, s::Spl, x::AbstractMatrix{<:Real})
78+
# `@inline` + `@boundscheck` allows users to skip bound checks by calling `@inbounds rand!(...)`
79+
# Ref https://docs.julialang.org/en/v1/devdocs/boundscheck/#Eliding-bounds-checks
80+
@boundscheck # ... check size (and possibly indices) of `x`
81+
# ... generate a single matrix sample from s in x
82+
end
83+
```
9484

9585
## Create a Distribution
9686

@@ -106,7 +96,7 @@ A univariate distribution type should be defined as a subtype of `DiscreteUnivar
10696

10797
The following methods need to be implemented for each univariate distribution type:
10898

109-
- [`rand(::AbstractRNG, d::UnivariateDistribution)`](@ref)
99+
- [`Base.rand(::AbstractRNG, d::UnivariateDistribution)`](@ref)
110100
- [`sampler(d::Distribution)`](@ref)
111101
- [`logpdf(d::UnivariateDistribution, x::Real)`](@ref)
112102
- [`cdf(d::UnivariateDistribution, x::Real)`](@ref)
@@ -138,8 +128,8 @@ The following methods need to be implemented for each multivariate distribution
138128

139129
- [`length(d::MultivariateDistribution)`](@ref)
140130
- [`sampler(d::Distribution)`](@ref)
141-
- [`eltype(d::Distribution)`](@ref)
142-
- [`Distributions._rand!(::AbstractRNG, d::MultivariateDistribution, x::AbstractArray)`](@ref)
131+
- [`Base.rand(::AbstractRNG, d::MultivariateDistribution)`](@ref)
132+
- [`Random.rand!(::AbstractRNG, d::MultivariateDistribution, x::AbstractVector{<:Real})`](@ref)
143133
- [`Distributions._logpdf(d::MultivariateDistribution, x::AbstractArray)`](@ref)
144134

145135
Note that if there exist faster methods for batch evaluation, one should override `_logpdf!` and `_pdf!`.
@@ -161,6 +151,7 @@ A matrix-variate distribution type should be defined as a subtype of `DiscreteMa
161151
The following methods need to be implemented for each matrix-variate distribution type:
162152

163153
- [`size(d::MatrixDistribution)`](@ref)
164-
- [`Distributions._rand!(rng::AbstractRNG, d::MatrixDistribution, A::AbstractMatrix)`](@ref)
154+
- [`Base.rand(rng::AbstractRNG, d::MatrixDistribution)`](@ref)
155+
- [`Random.rand!(rng::AbstractRNG, d::MatrixDistribution, A::AbstractMatrix{<:Real})`](@ref)
165156
- [`sampler(d::MatrixDistribution)`](@ref)
166157
- [`Distributions._logpdf(d::MatrixDistribution, x::AbstractArray)`](@ref)

docs/src/multivariate.md

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ The methods listed below are implemented for each multivariate distribution, whi
1818
```@docs
1919
length(::MultivariateDistribution)
2020
size(::MultivariateDistribution)
21-
eltype(::Type{MultivariateDistribution})
2221
mean(::MultivariateDistribution)
2322
var(::MultivariateDistribution)
2423
cov(::MultivariateDistribution)

docs/src/types.md

-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ The basic functionalities that a sampleable object provides are to *retrieve inf
5757
length(::Sampleable)
5858
size(::Sampleable)
5959
nsamples(::Type{Sampleable}, ::Any)
60-
eltype(::Type{Sampleable})
6160
rand(::AbstractRNG, ::Sampleable)
6261
rand!(::AbstractRNG, ::Sampleable, ::AbstractArray)
6362
```

src/censored.jl

-2
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,6 @@ function partype(d::Censored{<:UnivariateDistribution,<:ValueSupport,T}) where {
112112
return promote_type(partype(d.uncensored), T)
113113
end
114114

115-
Base.eltype(::Type{<:Censored{D,S,T}}) where {D,S,T} = promote_type(T, eltype(D))
116-
117115
#### Range and Support
118116

119117
isupperbounded(d::LeftCensored) = isupperbounded(d.uncensored)

src/cholesky/lkjcholesky.jl

-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@ end
8282
# Properties
8383
# -----------------------------------------------------------------------------
8484

85-
Base.eltype(::Type{LKJCholesky{T}}) where {T} = T
86-
8785
function Base.size(d::LKJCholesky)
8886
p = d.d
8987
return (p, p)

src/common.jl

+13-6
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,21 @@ Base.size(s::Sampleable{Univariate}) = ()
9494
Base.size(s::Sampleable{Multivariate}) = (length(s),)
9595

9696
"""
97-
eltype(::Type{Sampleable})
97+
eltype(::Type{S}) where {S<:Distributions.Sampleable}
98+
99+
The default element type of a sample from a sampler of type `S`.
100+
101+
This is the type of elements of the samples generated by the `rand` method.
102+
However, one can provide an array of different element types to store the samples using `rand!`.
103+
104+
!!! warn
105+
This method is deprecated and will be removed in an upcoming breaking release.
98106
99-
The default element type of a sample. This is the type of elements of the samples generated
100-
by the `rand` method. However, one can provide an array of different element types to
101-
store the samples using `rand!`.
102107
"""
103-
Base.eltype(::Type{<:Sampleable{F,Discrete}}) where {F} = Int
104-
Base.eltype(::Type{<:Sampleable{F,Continuous}}) where {F} = Float64
108+
function Base.eltype(::Type{S}) where {S<:Sampleable}
109+
Base.depwarn("`eltype(::Type{<:Distributions.Sampleable})` is deprecated and will be removed", :eltype)
110+
return Base.promote_op(eltype rand, S)
111+
end
105112

106113
"""
107114
nsamples(s::Sampleable)

src/multivariate/dirichlet.jl

-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ end
5050

5151
length(d::DirichletCanon) = length(d.alpha)
5252

53-
Base.eltype(::Type{<:Dirichlet{T}}) where {T} = T
54-
5553
#### Conversions
5654
convert(::Type{Dirichlet{T}}, cf::DirichletCanon) where {T<:Real} =
5755
Dirichlet(convert(AbstractVector{T}, cf.alpha))

src/multivariate/jointorderstatistics.jl

-2
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ maximum(d::JointOrderStatistics) = Fill(maximum(d.dist), length(d))
8888

8989
params(d::JointOrderStatistics) = tuple(params(d.dist)..., d.n, d.ranks)
9090
partype(d::JointOrderStatistics) = partype(d.dist)
91-
Base.eltype(::Type{<:JointOrderStatistics{D}}) where {D} = Base.eltype(D)
92-
Base.eltype(d::JointOrderStatistics) = eltype(d.dist)
9391

9492
function logpdf(d::JointOrderStatistics, x::AbstractVector{<:Real})
9593
n = d.n

src/multivariate/mvlogitnormal.jl

-2
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ canonform(d::MvLogitNormal{<:MvNormal}) = MvLogitNormal(canonform(d.normal))
5252
# Properties
5353

5454
length(d::MvLogitNormal) = length(d.normal) + 1
55-
Base.eltype(::Type{<:MvLogitNormal{D}}) where {D} = eltype(D)
56-
Base.eltype(d::MvLogitNormal) = eltype(d.normal)
5755
params(d::MvLogitNormal) = params(d.normal)
5856
@inline partype(d::MvLogitNormal) = partype(d.normal)
5957

src/multivariate/mvlognormal.jl

-2
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,6 @@ MvLogNormal(μ::AbstractVector,s::Real) = MvLogNormal(MvNormal(μ,s))
176176
MvLogNormal::AbstractVector) = MvLogNormal(MvNormal(σ))
177177
MvLogNormal(d::Int,s::Real) = MvLogNormal(MvNormal(d,s))
178178

179-
Base.eltype(::Type{<:MvLogNormal{T}}) where {T} = T
180-
181179
### Conversion
182180
function convert(::Type{MvLogNormal{T}}, d::MvLogNormal) where T<:Real
183181
MvLogNormal(convert(MvNormal{T}, d.normal))

src/multivariate/mvnormal.jl

-2
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,6 @@ Base.@deprecate MvNormal(μ::AbstractVector{<:Real}, σ::Real) MvNormal(μ, σ^2
223223
Base.@deprecate MvNormal::AbstractVector{<:Real}) MvNormal(LinearAlgebra.Diagonal(map(abs2, σ)))
224224
Base.@deprecate MvNormal(d::Int, σ::Real) MvNormal(LinearAlgebra.Diagonal(FillArrays.Fill^2, d)))
225225

226-
Base.eltype(::Type{<:MvNormal{T}}) where {T} = T
227-
228226
### Conversion
229227
function convert(::Type{MvNormal{T}}, d::MvNormal) where T<:Real
230228
MvNormal(convert(AbstractArray{T}, d.μ), convert(AbstractArray{T}, d.Σ))

src/multivariate/mvnormalcanon.jl

-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ length(d::MvNormalCanon) = length(d.μ)
154154
mean(d::MvNormalCanon) = convert(Vector{eltype(d.μ)}, d.μ)
155155
params(d::MvNormalCanon) = (d.μ, d.h, d.J)
156156
@inline partype(d::MvNormalCanon{T}) where {T<:Real} = T
157-
Base.eltype(::Type{<:MvNormalCanon{T}}) where {T} = T
158157

159158
var(d::MvNormalCanon) = diag(inv(d.J))
160159
cov(d::MvNormalCanon) = Matrix(inv(d.J))

src/multivariate/mvtdist.jl

-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ logdet_cov(d::GenericMvTDist) = d.df>2 ? logdet((d.df/(d.df-2))*d.Σ) : NaN
101101

102102
params(d::GenericMvTDist) = (d.df, d.μ, d.Σ)
103103
@inline partype(d::GenericMvTDist{T}) where {T} = T
104-
Base.eltype(::Type{<:GenericMvTDist{T}}) where {T} = T
105104

106105
# For entropy calculations see "Multivariate t Distributions and their Applications", S. Kotz & S. Nadarajah
107106
function entropy(d::GenericMvTDist)

src/multivariate/product.jl

-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ function Product(v::V) where {S<:ValueSupport,T<:UnivariateDistribution{S},V<:Ab
3131
end
3232

3333
length(d::Product) = length(d.v)
34-
function Base.eltype(::Type{<:Product{S,T}}) where {S<:ValueSupport,
35-
T<:UnivariateDistribution{S}}
36-
return eltype(T)
37-
end
3834

3935
_rand!(rng::AbstractRNG, d::Product, x::AbstractVector{<:Real}) =
4036
map!(Base.Fix1(rand, rng), x, d.v)

src/product.jl

-4
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,6 @@ const ArrayOfUnivariateDistribution{N,D,S<:ValueSupport,T} = ProductDistribution
7070
const FillArrayOfUnivariateDistribution{N,D<:Fill{<:Any,N},S<:ValueSupport,T} = ProductDistribution{N,0,D,S,T}
7171

7272
## General definitions
73-
function Base.eltype(::Type{<:ProductDistribution{<:Any,<:Any,<:Any,<:ValueSupport,T}}) where {T}
74-
return T
75-
end
76-
7773
size(d::ProductDistribution) = d.size
7874

7975
mean(d::ProductDistribution) = reshape(mapreduce(vec mean, vcat, d.dists), size(d))

src/reshaped.jl

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ function _reshape_check_dims(dist::Distribution{<:ArrayLikeVariate}, dims::Dims)
2424
end
2525

2626
Base.size(d::ReshapedDistribution) = d.dims
27-
Base.eltype(::Type{ReshapedDistribution{<:Any,<:ValueSupport,D}}) where {D} = eltype(D)
2827

2928
partype(d::ReshapedDistribution) = partype(d.dist)
3029
params(d::ReshapedDistribution) = (d.dist, d.dims)

src/truncate.jl

-3
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ end
126126
params(d::Truncated) = tuple(params(d.untruncated)..., d.lower, d.upper)
127127
partype(d::Truncated{<:UnivariateDistribution,<:ValueSupport,T}) where {T<:Real} = promote_type(partype(d.untruncated), T)
128128

129-
Base.eltype(::Type{<:Truncated{D}}) where {D<:UnivariateDistribution} = eltype(D)
130-
Base.eltype(d::Truncated) = eltype(d.untruncated)
131-
132129
### range and support
133130

134131
islowerbounded(d::RightTruncated) = islowerbounded(d.untruncated)

src/univariate/continuous/gumbel.jl

-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ Gumbel(μ::Real=0.0) = Gumbel(μ, one(μ); check_args=false)
4141

4242
const DoubleExponential = Gumbel
4343

44-
Base.eltype(::Type{Gumbel{T}}) where {T} = T
45-
4644
#### Conversions
4745

4846
convert(::Type{Gumbel{T}}, μ::S, θ::S) where {T <: Real, S <: Real} = Gumbel(T(μ), T(θ))

src/univariate/continuous/normal.jl

-2
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ params(d::Normal) = (d.μ, d.σ)
6060
location(d::Normal) = d.μ
6161
scale(d::Normal) = d.σ
6262

63-
Base.eltype(::Type{Normal{T}}) where {T} = T
64-
6563
#### Statistics
6664

6765
mean(d::Normal) = d.μ

src/univariate/discrete/bernoulli.jl

-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ Bernoulli() = Bernoulli{Float64}(0.5)
4040

4141
@distr_support Bernoulli false true
4242

43-
Base.eltype(::Type{<:Bernoulli}) = Bool
44-
4543
#### Conversions
4644
convert(::Type{Bernoulli{T}}, p::Real) where {T<:Real} = Bernoulli(T(p))
4745
Base.convert(::Type{Bernoulli{T}}, d::Bernoulli) where {T<:Real} = Bernoulli{T}(T(d.p))

src/univariate/discrete/bernoullilogit.jl

-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ BernoulliLogit() = BernoulliLogit(0.0)
2424

2525
@distr_support BernoulliLogit false true
2626

27-
Base.eltype(::Type{<:BernoulliLogit}) = Bool
28-
2927
#### Conversions
3028
Base.convert(::Type{BernoulliLogit{T}}, d::BernoulliLogit) where {T<:Real} = BernoulliLogit{T}(T(d.logitp))
3129
Base.convert(::Type{BernoulliLogit{T}}, d::BernoulliLogit{T}) where {T<:Real} = d

src/univariate/discrete/dirac.jl

-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ struct Dirac{T} <: DiscreteUnivariateDistribution
2222
value::T
2323
end
2424

25-
Base.eltype(::Type{Dirac{T}}) where {T} = T
26-
2725
insupport(d::Dirac, x::Real) = x == d.value
2826
minimum(d::Dirac) = d.value
2927
maximum(d::Dirac) = d.value

src/univariate/discrete/discretenonparametric.jl

-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ DiscreteNonParametric(vs::AbstractVector{T}, ps::AbstractVector{P}; check_args::
3939
T<:Real,P<:Real} =
4040
DiscreteNonParametric{T,P,typeof(vs),typeof(ps)}(vs, ps; check_args=check_args)
4141

42-
Base.eltype(::Type{<:DiscreteNonParametric{T}}) where T = T
43-
4442
# Conversion
4543
convert(::Type{DiscreteNonParametric{T,P,Ts,Ps}}, d::DiscreteNonParametric) where {T,P,Ts,Ps} =
4644
DiscreteNonParametric{T,P,Ts,Ps}(convert(Ts, support(d)), convert(Ps, probs(d)), check_args=false)

src/univariate/locationscale.jl

-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ end
7171
const ContinuousAffineDistribution{T<:Real,D<:ContinuousUnivariateDistribution} = AffineDistribution{T,Continuous,D}
7272
const DiscreteAffineDistribution{T<:Real,D<:DiscreteUnivariateDistribution} = AffineDistribution{T,Discrete,D}
7373

74-
Base.eltype(::Type{<:AffineDistribution{T}}) where T = T
75-
7674
minimum(d::AffineDistribution) =
7775
d.σ > 0 ? d.μ + d.σ * minimum(d.ρ) : d.μ + d.σ * maximum(d.ρ)
7876
maximum(d::AffineDistribution) =

src/univariate/orderstatistic.jl

-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ insupport(d::OrderStatistic, x::Real) = insupport(d.dist, x)
5858

5959
params(d::OrderStatistic) = tuple(params(d.dist)..., d.n, d.rank)
6060
partype(d::OrderStatistic) = partype(d.dist)
61-
Base.eltype(::Type{<:OrderStatistic{D}}) where {D} = Base.eltype(D)
62-
Base.eltype(d::OrderStatistic) = eltype(d.dist)
6361

6462
# distribution of the ith order statistic from an IID uniform distribution, with CDF Uᵢₙ(x)
6563
function _uniform_orderstatistic(d::OrderStatistic)

0 commit comments

Comments
 (0)