# LoadError: ArgumentError: Sampler for this object is not defined

**URL:** https://discourse.julialang.org/t/loaderror-argumenterror-sampler-for-this-object-is-not-defined/74796
**Category:** New to Julia
**Tags:** question, error, random
**Created:** [January 18, 2022, 11:58am UTC](https://discourse.julialang.org/t/loaderror-argumenterror-sampler-for-this-object-is-not-defined/74796 "2022-01-18T11:58:57Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![wccarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wccarleton/32/32635_2.png) [@wccarleton](https://discourse.julialang.org/u/wccarleton)
#### Post date: [January 18, 2022, 11:58am UTC](https://discourse.julialang.org/t/loaderror-argumenterror-sampler-for-this-object-is-not-defined/74796/1 "2022-01-18T11:58:57Z")

</div>

Hi All,

I’m learning Julia and coming from R and a bit of Python. To help me figure Julia out (in a way that’s directly related to my current work), I’ve decided to write a module based on the Vose/Walker Alias method for sampling randomly from arbitrary discrete distributions. I realize there are some relevant functions in the StatsBase and Distributions packages, but I find learning through errors is helpful. I have encountered an error, though, that’s proven to be hard for me to resolve on my own and I’m hoping someone can point me in the right direction. I’m sure this problem boils down to confusion about Types and how to work with them properly.

Here’s the code:

```julia
#= implement the Vose algorithm in Julia http://www.keithschwarz.com/darts-dice-coins/
=#

using Random

import Base.rand
import Random: Sampler, SamplerSimple, SamplerTrivial, Repetition, eltype

rng = MersenneTwister()

n = 5
a = collect(1:n)
b = collect(1:n)
c = rand(Float32,n)

# discrete distribution struct
struct DiscreteDistribution
    prob::Vector
    support::Vector
end

struct AliasTable
    prob::Vector
    support::Vector
    accept::Vector
    alias::Vector
end

dd = DiscreteDistribution(c,a)

# build alias table
function vose_method(dd::DiscreteDistribution)
    n_prob = length(dd.prob)
    n_support = length(dd.support)
    sum_prob = sum(dd.prob)
    prob_scaled = dd.prob * n_prob
    accept = Vector(undef, n_prob)
    alias = Vector{typeof(dd.support[1])}(undef, n_prob)
    small = collect(1:n_prob)[prob_scaled .< 1]
    large = collect(1:n_prob)[prob_scaled .>= 1]
    while length(large) > 0 && length(small) > 0
        s = popfirst!(small)
        l = popfirst!(large)
        accept[s] = prob_scaled[s]
        alias[s] = dd.support[l]
        prob_scaled[l] = (prob_scaled[l] + prob_scaled[s]) - 1
        prob_scaled[l] < 1 ? push!(small, l) : push!(large, l)
    end
    while length(large) > 0
        l = popfirst!(large)
        accept[l] = 1
    end
    while length(small) > 0
        s = popfirst!(small)
        accept[s] = 1
    end
    return AliasTable(dd.prob, dd.support, accept, alias)
end

# sampling method
function sample_vose(rng, aliastable::AliasTable)
    j = rand(rng, 1:length(aliastable.support))
    outcome = rand(rng) <= aliastable.prob[j] ? aliastable.support[j] : aliastable.alias[j]
end

# new sampler
function Random.Sampler(::Type{<:AbstractRNG}, d::DiscreteDistribution, ::Repetition)
    SamplerSimple(d, vose_method(d))
end

Random.eltype(::Type{<:DiscreteDistribution}) = Int

sp = Random.Sampler(rng, dd)

isa(sp, SamplerSimple{<:DiscreteDistribution})

# extending rand
function Random.rand(rng::Type{<:AbstractRNG}, sp::SamplerSimple{<:DiscreteDistribution})
    sample_vose(rng, sp.data)
end

rand(rng, sp)

```

The last function call returns the error,

`LoadError: ArgumentError: Sampler for this object is not defined`

But, `isa(sp, SamplerSimple{<:DiscreteDistribution})` returns `true`, so I’m not sure where the dispatch is running into problems.

Any information would be greatly appreciated. I did read the docs in the Standard Library for the Random module and was able to produce a similar error when the example function `make_alias_table` is defined to return a custom type (without that, if it returns a vector for example, the dispatch seems to work as expected). But, I can’t see why that’s not working either. In case it helps, here’s the code for the example straight out of the docs with the modification to `make_alias_table` just described,

```julia
using Random

import Base.rand
import Random: Sampler, SamplerSimple, Repetition, eltype

rng = MersenneTwister()

struct DiscreteDistribution
    probabilities::Vector
end

struct OtherType
    b::Vector
end

Random.eltype(::Type{<:DiscreteDistribution}) = Int

dd = DiscreteDistribution([0.2,0.2,0.2,0.2,0.2])

function make_alias_table(p)
    OtherType(p)
end

function Random.Sampler(::Type{<:AbstractRNG}, distribution::DiscreteDistribution, ::Repetition)
    SamplerSimple(distribution, make_alias_table(distribution.probabilities))
end

sp = Sampler(rng, dd)

function draw_number(rng, sp)
    rand(rng, sp.data)
end

function rand(rng::AbstractRNG, sp::SamplerSimple{<:DiscreteDistribution})
    draw_number(rng, sp)
end

```

Many thanks for any help!  
Chris

---

<div class="post-metadata">

### Author: ![rfourquet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rfourquet/32/3610_2.png) [@rfourquet](https://discourse.julialang.org/u/rfourquet)
#### Post date: [January 19, 2022, 12:39pm UTC](https://discourse.julialang.org/t/loaderror-argumenterror-sampler-for-this-object-is-not-defined/74796/2 "2022-01-19T12:39:26Z")

</div>

I looked only at the simplified second example, the problem is that in your `draw_number` function, you call `rand` on `sp.data` which is of type `OtherType`, but you didn’t define what this should do. When `OtherType` is replaced with `Vector`, the `Random` module already knows how to sample from that. So you can for example add

```julia
Random.Sampler(::Type{RNG}, ot::OtherType, n::Repetition) where {RNG<:AbstractRNG} =
    SamplerSimple(ot, Sampler(RNG, ot.b, n))

rand(rng::AbstractRNG, sp::SamplerSimple{<:OtherType}) = rand(rng, sp.data)

```

---

<div class="post-metadata">

### Author: ![wccarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wccarleton/32/32635_2.png) [@wccarleton](https://discourse.julialang.org/u/wccarleton)
#### Post date: [January 19, 2022, 1:02pm UTC](https://discourse.julialang.org/t/loaderror-argumenterror-sampler-for-this-object-is-not-defined/74796/3 "2022-01-19T13:02:57Z")

</div>

Ah of course. I think that’s probably it. I’ll double check and then mark this as the solution. Thanks!

---

<div class="post-metadata">

### Author: ![wccarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wccarleton/32/32635_2.png) [@wccarleton](https://discourse.julialang.org/u/wccarleton)
#### Post date: [January 25, 2022, 2:04pm UTC](https://discourse.julialang.org/t/loaderror-argumenterror-sampler-for-this-object-is-not-defined/74796/4 "2022-01-25T14:04:54Z")

</div>

Okay, so you were right about the simplified example. Once corrected, I was then able to track down the type mismatch in the signature for the call to rand in the first example. Apparently, julia did not like the variable rng having the type constraint of ‘Type{\<:AbstractRNG}’. After changing it to simply ‘rng::AbstractRNG’ (as it appeared in the simplified example), the first example worked. I don’t understand why yet. But, for those interested and maybe working through the documentation as I was, here’s the revised code for the first example that appears to be working:

```julia
#= implement the Vose algorithm in Julia http://www.keithschwarz.com/darts-dice-coins/
=#

using Random

import Base.rand
import Random: Sampler, SamplerSimple, SamplerTrivial, Repetition, eltype

rng = MersenneTwister()

n = 5
a = collect(1:n)
b = collect(1:n)
c = rand(Float32,n)

# discrete distribution struct
struct DiscreteDistribution
    prob::Vector
    support::Vector
end

struct AliasTable
    prob::Vector
    support::Vector
    accept::Vector
    alias::Vector
end

dd = DiscreteDistribution(c,a)

# build alias table
function vose_method(dd::DiscreteDistribution)
    n_prob = length(dd.prob)
    n_support = length(dd.support)
    sum_prob = sum(dd.prob)
    prob_scaled = dd.prob * n_prob
    accept = Vector(undef, n_prob)
    alias = Vector{typeof(dd.support[1])}(undef, n_prob)
    small = collect(1:n_prob)[prob_scaled .< 1]
    large = collect(1:n_prob)[prob_scaled .>= 1]
    while length(large) > 0 && length(small) > 0
        s = popfirst!(small)
        l = popfirst!(large)
        accept[s] = prob_scaled[s]
        alias[s] = dd.support[l]
        prob_scaled[l] = (prob_scaled[l] + prob_scaled[s]) - 1
        prob_scaled[l] < 1 ? push!(small, l) : push!(large, l)
    end
    while length(large) > 0
        l = popfirst!(large)
        accept[l] = 1
    end
    while length(small) > 0
        s = popfirst!(small)
        accept[s] = 1
    end
    return AliasTable(dd.prob, dd.support, accept, alias)
end

# sampling method
function sample_vose(rng, aliastable::AliasTable)
    j = rand(rng, 1:length(aliastable.support))
    outcome = rand(rng) <= aliastable.prob[j] ? aliastable.support[j] : aliastable.alias[j]
end

# new sampler
function Random.Sampler(::Type{<:AbstractRNG}, dd::DiscreteDistribution, ::Repetition)
    SamplerSimple(dd, vose_method(dd))
end

sp = Random.Sampler(rng, dd)

# extending rand
function rand(rng::AbstractRNG, sp::SamplerSimple{<:DiscreteDistribution})
    sample_vose(rng, sp.data)
end

rand(rng, sp)

```

If anyone can explain the difference, then, between rng::Type{\<:AbstractRNG} and rng::AbstractRNG to me, I’d appreciate it. And, why does it seem to work in the call to Random.Sampler, but not in the call to rand?

---

<div class="post-metadata">

### Author: ![StevenWhitaker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevenwhitaker/32/9749_2.png) [@StevenWhitaker](https://discourse.julialang.org/u/StevenWhitaker)
#### Post date: [January 25, 2022, 2:57pm UTC](https://discourse.julialang.org/t/loaderror-argumenterror-sampler-for-this-object-is-not-defined/74796/5 "2022-01-25T14:57:44Z")

</div>

`rand` expects an `AbstractRNG` object, not a type. It’s like the difference between `1` and `Integer`; `1` is an instance of an `Int <: Integer`, whereas `Integer` is a type. Hopefully this example helps illustrate:

```julia
julia> f(a::Integer) = a
f (generic function with 1 method)

julia> f(::Type{<:Integer}) = "f(Integer) was called"
f (generic function with 2 methods)

julia> f(1)
1

julia> f(Int)
"f(Integer) was called"

```

> [@wccarleton](#):
>
> And, why does it seem to work in the call to Random.Sampler, but not in the call to rand?

`rand` wants an `AbstractRNG` object, whereas `Random.Sampler` just wants the type. Not sure why `Random.Sampler` just needs the type though.

---

<div class="post-metadata">

### Author: ![wccarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wccarleton/32/32635_2.png) [@wccarleton](https://discourse.julialang.org/u/wccarleton)
#### Post date: [January 26, 2022, 9:44am UTC](https://discourse.julialang.org/t/loaderror-argumenterror-sampler-for-this-object-is-not-defined/74796/6 "2022-01-26T09:44:41Z")

</div>

Of course, I see it now. Thanks!

---

<div class="post-metadata">

### Author: ![rfourquet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rfourquet/32/3610_2.png) [@rfourquet](https://discourse.julialang.org/u/rfourquet)
#### Post date: [January 27, 2022, 8:32am UTC](https://discourse.julialang.org/t/loaderror-argumenterror-sampler-for-this-object-is-not-defined/74796/7 "2022-01-27T08:32:57Z")

</div>

> [@StevenWhitaker](#):
>
> Not sure why `Random.Sampler` just needs the type though.

Generating a random value has two stages, calling `Sampler` and then calling `rand`. `Sampler` is not meant to consume entropy bits (only `rand` is), so the rng type is enough.
