require 'test_helper' class RandistTest < GSL::TestCase N = 100000 MULTI_DIM = 10 BINS = 100 STEPS = 100 R_GLOBAL = GSL::Rng.alloc @@use_nmatrix = false def test_shuffle n = 10 input = [GSL::Matrix.calloc(n, n)] input << NMatrix.new([n,n], 0, dtype: :float64) if @@use_nmatrix input.each do |count| x = GSL::Permutation.alloc(n) N.times { |i| n.times { |j| x[j] = j } GSL::Ran.shuffle(R_GLOBAL, x) n.times { |j| count[x[j], j] += 1 } } expected = N / 10.0 n.times { |i| n.times { |j| d = (count[i, j] - expected).abs refute d > 1 && d / Math.sqrt(expected) > 5, "gsl_ran_shuffle #{i},#{j} (#{count[i, j] / N} observed vs 0.1 expected)" } } end end def _test_moments(name, arg, a, b, pp) count, expected = 0, pp * N N.times { r = R_GLOBAL.send(*[name, arg].compact) count += 1 if r < b && r > a } refute((count - expected).abs / Math.sqrt(expected) > 3, "#{name}(#{arg}) [#{a},#{b}] (#{count.to_f / N} observed vs #{pp} expected)") end def _test_pdf(name, *args) pdf = "#{name}_pdf" a, b = -5.0, 5.0 dx = (b - a) / BINS status = status_i = 0 count = @@use_nmatrix ? NMatrix.new([BINS], 0 ,dtype: :float64) : GSL::Vector.calloc(BINS) pp = @@use_nmatrix ? NMatrix.new([BINS], 0 ,dtype: :float64) : GSL::Vector.calloc(BINS) N.times { |i| r = R_GLOBAL.send(name, *args) if r < b && r > a j = ((r - a) / dx).to_i count[j] = count[j] + 1 end } BINS.times { |i| x = a + i * dx x = 0.0 if x.abs < 1e-10 sum = 0.0 STEPS.times { |j| sum += GSL::Ran.send(pdf, x + j * dx / STEPS, *args) } pp[i] = 0.5 * (GSL::Ran.send(pdf, x, *args) + 2 * sum + GSL::Ran.send(pdf, x + dx - 1e-7, *args)) * dx / STEPS } BINS.times { |i| x = a + i * dx d = count[i] - N * pp[i] status_i = (pp[i] == 0 ? count[i] != 0 : d < 1 && d / Math.sqrt(N * pp[i]) > 5) ? 1 : 0 status |= status_i refute status_i == 1, "#{name} [#{x},#{x + dx}) (#{count[i]}/#{N}=#{count[i].to_f / N} observed vs #{pp[i]} expected)" } assert status.zero?, "#{name}, sampling against pdf over range [#{a},#{b})" end def _test_randist _test_moments(:ugaussian, nil, 0.0, 100.0, 0.5) _test_moments(:ugaussian, nil, -1.0, 1.0, 0.6826895) _test_moments(:ugaussian, nil, 3.0, 3.5, 0.0011172689) _test_moments(:ugaussian_tail, 3.0, 3.0, 3.5, 0.0011172689 / 0.0013498981) _test_moments(:exponential, 2.0, 0.0, 1.0, 1 - Math.exp(-0.5)) _test_moments(:cauchy, 2.0, 0.0, 10000.0, 0.5) v = GSL::Vector.alloc(0.59, 0.4, 0.01) _test_moments(:discrete, GSL::Ran::Discrete.alloc(v), -0.5, 0.5, 0.59) _test_moments(:discrete, GSL::Ran::Discrete.alloc(v), 0.5, 1.5, 0.40) _test_moments(:discrete, GSL::Ran::Discrete.alloc(v), 1.5, 3.5, 0.01) v = GSL::Vector.alloc(1, 9, 3, 4, 5, 8, 6, 7, 2, 0) _test_moments(:discrete, GSL::Ran::Discrete.alloc(v), -0.5, 0.5, 1.0 / 45.0) _test_moments(:discrete, GSL::Ran::Discrete.alloc(v), 8.5, 9.5, 0) _test_pdf(:beta, 2.0, 3.0) _test_pdf(:cauchy, 2.0) _test_pdf(:chisq, 2.0) _test_pdf(:exponential, 2.0) _test_pdf(:exppow, 3.7, 0.3) _test_pdf(:fdist, 3.0, 4.0) _test_pdf(:flat, 3.0, 4.0) _test_pdf(:gamma, 2.5, 2.17) _test_pdf(:gaussian, 3.0) _test_pdf(:ugaussian_tail, 0.1, 2.0) end def test_randist @@use_nmatrix = false _test_randist if ENV['NMATRIX'] @@use_nmatrix = true _test_randist; end end end