SciML / SciML/PoissonRandom.jl

Delete package?

Open
#6 9 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Julia
Stars
20
Forks
6
Avg merge
1h 45m
Merged PRs (30d)
4

Description

In the following benchmarks the samplers in Distributions are as fast as the implementations in this package:

using Distributions, PoissonRandom, StatsFuns
using Plots

function n_count(rng, λ, n)
  tmp = 0
  for i in 1:n
    tmp += PoissonRandom.count_rand(rng,λ)
  end
  tmp
end

function n_pois(rng,λ,n)
  tmp = 0
  for i in 1:n
    tmp += pois_rand(rng,λ)
  end
  tmp
end

function n_ad(rng, λ, n)
  tmp = 0
  for i in 1:n
    tmp += PoissonRandom.ad_rand(rng, λ)
  end
  tmp
end

function n_dist(λ,n)
  tmp = 0
  for i in 1:n
    tmp += rand(Poisson(λ))
  end
  tmp
end

function n_rfunctions(λ, n)
  tmp = 0
  for i in 1:n
    tmp += convert(Int, StatsFuns.RFunctions.poisrand(λ))
  end
  tmp
end

function n_countsampler(rng, λ::Float64, n)
  tmp = 0
  for i in 1:n
    tmp += rand(rng, Distributions.PoissonCountSampler(λ))
  end
  tmp
end

function n_adsampler(rng, λ::Float64, n)
  tmp = 0
  for i in 1:n
    tmp += rand(rng, Distributions.PoissonADSampler(λ))
  end
  tmp
end

function time_λ!(rng, times, λ::Float64, n)
  times[1] = @elapsed n_count(rng, λ, n)
  times[2] = @elapsed n_ad(rng, λ, n)
  times[3] = @elapsed n_pois(rng, λ, n)
  times[4] = @elapsed n_dist(λ, n)
  times[5] = @elapsed n_rfunctions(λ, n)
  times[6] = @elapsed n_countsampler(rng, λ, n)
  times[7] = @elapsed n_adsampler(rng, λ, n)

  nothing
end

function plot_benchmark(rng)
    times = Matrix{Float64}(undef, 7, 20)

    # Compile
    time_λ!(rng, view(times, :, 1), 5, 5_000_000)

    # Run with a bunch of λ
    for λ in 1:20
        time_λ!(rng, view(times, :, λ), float(λ), 5_000_000)
    end

    plot(times',
         labels = ["count_rand", "ad_rand", "pois_rand", "Distributions",
                   "RFunctions", "PoissonCountSampler", "PoissonADSampler"],
         lw = 3)
end

I get

using Random
Random.seed!(1234)
plot_benchmark(Random.GLOBAL_RNG)
savefig("global_rng.png")

image

and

using RandomNumbers
plot_benchmark(Xorshifts.Xoroshiro128Plus(1234))
savefig("xoroshiro128plus.png")

image

Actually, performing the benchmarks of n_count and n_ad with integer values for λ (as done in the README) leads to subpar performance compared with Distributions. For n_count this is probably due to the comparison of integer and float values in https://github.com/JuliaDiffEq/PoissonRandom.jl/blob/master/src/PoissonRandom.jl#L11, as @code_typed indicates:

julia> @code_typed PoissonRandom.count_rand(Random.GLOBAL_RNG, 5)
CodeInfo(
1 ─ %1  = invoke PoissonRandom.randexp(_2::MersenneTwister)::Float64
2 ┄ %2  = φ (#1 => 0, #3 => %14)::Int64
│   %3  = φ (#1 => %1, #3 => %16)::Float64
│   %4  = (Base.sitofp)(Float64, λ)::Float64
│   %5  = (Base.lt_float)(%3, %4)::Bool
│   %6  = (Base.eq_float)(%3, %4)::Bool
│   %7  = (Base.lt_float)(%4, 9.22337e18)::Bool
│   %8  = (Base.and_int)(%6, %7)::Bool
│   %9  = (Base.fptosi)(Int64, %4)::Int64
│   %10 = (Base.slt_int)(%9, λ)::Bool
│   %11 = (Base.and_int)(%8, %10)::Bool
│   %12 = (Base.or_int)(%5, %11)::Bool
└──       goto #4 if not %12
3 ─ %14 = (Base.add_int)(%2, 1)::Int64
│   %15 = invoke PoissonRandom.randexp(_2::MersenneTwister)::Float64
│   %16 = (Base.add_float)(%3, %15)::Float64
└──       goto #2
4 ─       return %2
) => Int64

julia> @code_typed PoissonRandom.count_rand(Random.GLOBAL_RNG, 5.0)
CodeInfo(
1 ─ %1 = invoke PoissonRandom.randexp(_2::MersenneTwister)::Float64
2 ┄ %2 = φ (#1 => 0, #3 => %6)::Int64
│   %3 = φ (#1 => %1, #3 => %8)::Float64
│   %4 = (Base.lt_float)(%3, λ)::Bool
└──      goto #4 if not %4
3 ─ %6 = (Base.add_int)(%2, 1)::Int64
│   %7 = invoke PoissonRandom.randexp(_2::MersenneTwister)::Float64
│   %8 = (Base.add_float)(%3, %7)::Float64
└──      goto #2
4 ─      return %2
) => Int64

julia> @code_typed rand(Random.GLOBAL_RNG, Distributions.PoissonCountSampler(5.0))
CodeInfo(
1 ─ %1 = (Base.getfield)(s, :μ)::Float64
└── %2 = invoke Distributions.randexp(_2::MersenneTwister)::Float64
2 ┄ %3 = φ (#1 => 0, #3 => %7)::Int64
│   %4 = φ (#1 => %2, #3 => %9)::Float64
│   %5 = (Base.lt_float)(%4, %1)::Bool
└──      goto #4 if not %5
3 ─ %7 = (Base.add_int)(%3, 1)::Int64
│   %8 = invoke Distributions.randexp(_2::MersenneTwister)::Float64
│   %9 = (Base.add_float)(%4, %8)::Float64
└──      goto #2
4 ─      return %3
) => Int64

Hence, should we deprecate this package by adding a deprecation warning to pois_rand? How many DiffEq packages depend on PoissonRandom? Would it be sufficient to implement pois_rand (if we want to keep it) in DiffEqJump using the samplers in Distributions?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the benchmark code and README, then inspect src/PoissonRandom.jl around the linked comparison and the Distributions sampler behavior. Check which DiffEq packages depend on PoissonRandom and review DiffEqJump as a possible location. Done requires a maintainer decision on deprecation, retention, or replacement, with the affected dependencies and migration scope documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
julia
Domain
performance
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.