# Find types of arguments of a function's method

Suppose I wanna compute the mean of every distribution in Distributions.jl.
I create a vector w/ all distributions then loop through each & compute the mean.
Thanks to @tfehring for showing me how to pull all the distributions.

``````using Distributions
subtypes(Distribution) #Vector{Any} with 78 elements

D_m = []; E_m = []; #
for d = subtypes(Distribution)
try
fn = mean(d())
push!(D_m, [d, fn])
catch e
println("Err ", d, e)
push!(E_m, [d, e])
end
end
``````

This works for distributions w/ default parameters:
Example: `mean(Arcsine())`

It does not work for distributions w/o default parameter values:
Example: Chi(Î˝) has one parameter w/ no default values.

I need help w/ the following, as I loop over a distribution â€śdâ€ť w/o default parameter values:

1. for simplicity letâ€™s choose the first method
methods(d).ms[1]
Example Chi: methods(Chi).ms[1] gives: `(::Type{Chi})(Î˝::Integer)`
2. find the number of arguments in the first method
3. find the required type of each argument in the first method (real number, matrix etc)
4. fill in some arbitrary legal values for each parameter in the first method
Use the simplest for each. Eg if itâ€™s a matrix, set mu= [0], sigma=[1]â€¦
5. compute the mean

This turned out to be non-trivial for me.
Yes, I realize some of these distributions are abstract structures for which it wonâ€™t be possible.

Which step is the problem?

The number and types of arguments are `methods(d).ms[1].sig`. It looks like itâ€™s a tuple where the first element is `typeof(d)`, and the rest (`Base.tail`) are the types of expected arguments.

To provide a value of an arbitrary type is the most difficult part to me, Iâ€™ve no idea how to do that in a generic way, thereâ€™s only hope that thereâ€™s a method which accepts types you know how to instantiate.

1 Like

@Vasily_Pisarev
My goal is to compute the mean of every distribution.

1. If it has default values for parameters then: `mean(Normal())`
2. If not, to automatically set legal parameter values.
`Chi()` doesnâ€™t work bc it doesnâ€™t have a default parameter.
methods(Chi).ms[1] tells me it has 1 param which is an Integer: `(::Type{Chi})(Î˝::Integer)`
I want the loop to automatically: `mean(Chi(1))`
This can be tricky: `methods(NormalInverseGaussian).ms[1]` has four param, all integers
I want: `mean(NormalInverseGaussian(1,1,1,1))`
`methods(MvNormal).ms[1]`: (ÎĽ::AbstractArray{T,1}, ÎŁ::PDMats.AbstractPDMat{T}) where T<:Real
I want: `mean(MvNormal([1],[1]))`
I want the loop to do this all automatically.

For each method signature in the table, you have a tuple-type like `Tuple{Type{Uniform}, Integer}`. You can do `Base.tail(Tuple(tuptype.parameters))` to get the â€śeverything elseâ€ť of that method. From there I suppose you could try calling `one` on everything in that list and hoping thereâ€™s a method out there . Assuming this works for you, you could ostensibly do it like: `distr(one.(the_tail)...)`

Just as a heads up, I generated the full list (of â€śfirstâ€ť methods) with

`````` map(x-> isabstracttype(x) ? nothing : methods(x).ms[1].sig, subtypes(Distribution))
``````

and took a look through it. Thereâ€™s some definite oddballs that will give you a hard time time. e.g.

``````Tuple{Type{DirichletMultinomial},Integer,Array{T,1}} where T<:Integer    # default array size?
Tuple{Type{Truncated},Distribution{Univariate,S} where S<:ValueSupport,Integer,Integer}    # default distribution?
``````

You are running into difficulties because this is an ill-defined problem: mostly, the vocabulary of Distributions.jl is not distributions, but functions that generate distributions (constructors). The distinction is important.

What you would need is either an API that allows you to query the space of valid arguments, or generates â€śsomeâ€ť valid instance of each distribution class. Neither exists, because it is a pretty rare use case.

What are you trying to accomplish?

1 Like