Browse Source

Move architecture

pull/2/head
Arthur POULET 4 years ago
parent
commit
730f4f04f9
No known key found for this signature in database GPG Key ID: FC154EA63FF5D8BC
  1. 32
      spec/binomial_distribution.cr
  2. 22
      spec/normale_distribution.cr
  3. 16
      src/lib/binomial_distribution.cr
  4. 1
      src/lib/math.cr
  5. 10
      src/lib/math/big_number.cr
  6. 27
      src/lib/math/coef_binomial.cr
  7. 2
      src/lib/math/exceptions.cr
  8. 3
      src/lib/math/factorial.cr
  9. 0
      src/lib/math/numeric_value.cr
  10. 20
      src/lib/normale_distribution.cr
  11. 33
      src/lib/normale_distribution/persistant.cr
  12. 7
      src/stats.cr
  13. 21
      src/stats/math/coef_binomial.cr
  14. 13
      src/stats/math/numeric_value.cr
  15. 17
      src/stats/normale_distribution.cr
  16. 34
      src/stats/normale_distribution/persistant.cr

32
spec/binomial_distribution.cr

@ -1,3 +1,5 @@
include Stats
describe Math do
it "binomial_distribution" do
0.0.step(by: 0.1, to: 1.0) do |proba|
@ -10,23 +12,23 @@ end
describe BinomialDistribution do
it "initialize" do
BinomialDistribution.new(0).should be_a(BinomialDistribution)
BinomialDistribution.new(1).should be_a(BinomialDistribution)
BinomialDistribution.new(100).should be_a(BinomialDistribution)
BinomialDistribution.new(1, 0).should be_a(BinomialDistribution)
BinomialDistribution.new(1, 0.5).should be_a(BinomialDistribution)
BinomialDistribution.new(1, 1).should be_a(BinomialDistribution)
BinomialDistribution(Int32, Float64).new(0).should be_a(BinomialDistribution(Int32, Float64))
BinomialDistribution(Int32, Float64).new(1).should be_a(BinomialDistribution(Int32, Float64))
BinomialDistribution(Int32, Float64).new(100).should be_a(BinomialDistribution(Int32, Float64))
BinomialDistribution(Int32, Int32).new(1, 0).should be_a(BinomialDistribution(Int32, Int32))
BinomialDistribution(Int32, Float64).new(1, 0.5).should be_a(BinomialDistribution(Int32, Float64))
BinomialDistribution(Int32, Int32).new(1, 1).should be_a(BinomialDistribution(Int32, Int32))
end
it "initialize errors" do
expect_raises { BinomialDistribution.new(-1) }
expect_raises { BinomialDistribution.new(0, -1) }
expect_raises { BinomialDistribution.new(0, 1.5) }
expect_raises { BinomialDistribution(Int32, Float64).new(-1) }
expect_raises { BinomialDistribution(Int32, Int32).new(0, -1) }
expect_raises { BinomialDistribution(Int32, Float64).new(0, 1.5) }
end
it "distribute" do
b = BinomialDistribution.new(2, 0.5)
b.should be_a(BinomialDistribution)
b = BinomialDistribution(Int32, Float64).new(2, 0.5)
b.should be_a(BinomialDistribution(Int32, Float64))
b.distribute(0).should eq 0.25
b.distribute(1).should eq 0.5
b.distribute(2).should eq 0.25
@ -39,10 +41,10 @@ describe BinomialDistribution do
end
it "with BitNumber" do
BinomialDistribution.new(BigInt.new(1), BigFloat.new(1)).should be_a(BinomialDistribution)
((a = BinomialDistribution.new(BigInt.new(10), BigFloat.new(0.02)).distribute(BigInt.new(1)..BigInt.new(10))) > 0.02).should be_true
((b = BinomialDistribution.new(BigInt.new(20), BigFloat.new(0.02)).distribute(BigInt.new(1)..BigInt.new(20))) > 0.02).should be_true
((c = BinomialDistribution.new(BigInt.new(50), BigFloat.new(0.02)).distribute(BigInt.new(1)..BigInt.new(50))) > 0.02).should be_true
BinomialDistribution(BigInt, BigFloat).new(BigInt.new(1), BigFloat.new(1)).should be_a(BinomialDistribution(BigInt, BigFloat))
((a = BinomialDistribution(BigInt, BigFloat).new(BigInt.new(10), BigFloat.new(0.02)).distribute(BigInt.new(1)..BigInt.new(10))) > 0.02).should be_true
((b = BinomialDistribution(BigInt, BigFloat).new(BigInt.new(20), BigFloat.new(0.02)).distribute(BigInt.new(1)..BigInt.new(20))) > 0.02).should be_true
((c = BinomialDistribution(BigInt, BigFloat).new(BigInt.new(50), BigFloat.new(0.02)).distribute(BigInt.new(1)..BigInt.new(50))) > 0.02).should be_true
(b > a).should be_true
(c > b).should be_true
# p a, b, c

22
spec/normale_distribution.cr

@ -1,3 +1,5 @@
include Stats
describe NormaleDistribution do
it "between" do
bet = NormaleDistribution.between standard_deviation: 1, esperance: 0, min: -1, max: 1
@ -9,13 +11,13 @@ end
describe NormaleDistribution::Persistant do
it "instances" do
NormaleDistribution::Persistant.new
NormaleDistribution::Persistant.new(standard_deviation: 12).standard_deviation.should eq(12)
NormaleDistribution::Persistant.new(esperance: 14).esperance.should eq(14)
NormaleDistribution::Persistant(Float64, Float64).new
NormaleDistribution::Persistant(Int32, Float64).new(standard_deviation: 12).standard_deviation.should eq(12)
NormaleDistribution::Persistant(Float64, Int32).new(esperance: 14).esperance.should eq(14)
end
it "instances with BigNumber" do
n = NormaleDistribution::Persistant.new(
n = NormaleDistribution::Persistant(BigInt, BigFloat).new(
standard_deviation: BigInt.new(1),
esperance: BigFloat.new(1))
n.standard_deviation.should eq(1)
@ -23,14 +25,14 @@ describe NormaleDistribution::Persistant do
end
it "QI" do
rule = NormaleDistribution::Persistant.new standard_deviation: 15, esperance: 100
rule = NormaleDistribution::Persistant(Int32, Int32).new standard_deviation: 15, esperance: 100
rule.between(85, 115).round(2).should eq(0.68)
end
it "centroid" do
[0.1, 1, 2, 4.1324].each do |space|
[0, 1, -1, 12, 41, 0.2, 0.233].each do |center|
rule = NormaleDistribution::Persistant.new standard_deviation: space, esperance: center
[0.1, 1.0, 2.0, 4.1324].each do |space|
[0.0, 1.0, -1.0, 12.0, 41.0, 0.2, 0.233].each do |center|
rule = NormaleDistribution::Persistant(Float64, Float64).new standard_deviation: space, esperance: center
[0.2, 0.4, 0.45, 0.55, 0.94, 1.1].each do |diff|
(-rule.between(diff, center)).should eq(rule.between(center, diff))
end
@ -39,7 +41,7 @@ describe NormaleDistribution::Persistant do
end
it "must fail" do
expect_raises { NormaleDistribution::Persistant.new standard_deviation: -1 }
expect_raises { NormaleDistribution::Persistant.new standard_deviation: 0 }
expect_raises { NormaleDistribution::Persistant(Int32, Float64).new standard_deviation: -1 }
expect_raises { NormaleDistribution::Persistant(Int32, Float64).new standard_deviation: 0 }
end
end

16
src/stats/binomial_distribution.cr → src/lib/binomial_distribution.cr

@ -1,10 +1,11 @@
class BinomialDistribution
@n : Int::All
@p : Number::All
class Stats::BinomialDistribution(N, P)
@n : N
@p : P
# @param n [Fixnum] number of tries
# @param p [Float] probability of success
# @note if no probability is defined, the default value will be 0.5
#
# NOTE if no probability is defined, the default value will be 0.5
def initialize(@n, @p = 0.5)
raise Math::DomainError.new "The argument `p` `#{@p}` is not in greater or equal to 0" if @p < 0.0
raise Math::DomainError.new "The argument `p` `#{@p}` is not in lesser or equal to 1" if @p > 1.0
@ -16,15 +17,14 @@ class BinomialDistribution
end
# @param k [Fixnum] number of test successful.
# @return [Float] probability
#  TODO : Enumerable of Int
#
# TODO : Enumerable of Int
def distribute(k : Enumerable)
k.map { |p| distribute(p) }.reduce { |a, b| a + b }
end
# @param k [Enumerable] list of number of test successful.
# @return [Float] probability
def distribute(k : Int::All)
def distribute(k : Int)
raise Math::SuperiorityError.new "the number of success must be lesser or equal to the number of tries (#{@n})" if k > @n
Math.coef_binomial(@n, k) * (@p**k) * ((1 - @p) ** (@n - k))
end

1
src/lib/math.cr

@ -0,0 +1 @@
require "./math/*"

10
src/stats/math/big_number.cr → src/lib/math/big_number.cr

@ -1,20 +1,28 @@
# This file defines new operations on big numbers with native data types
# :nodoc:
require "big_int"
# :nodoc:
require "big_float"
{% for klass in [Float32, Float64, Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64] %}
# :nodoc:
struct {{klass}}
{% for op in ["+", "-", "*", "%", "/"] %}
{% for other_klass in [BigFloat, BigInt] %}
# :nodoc:
def {{op.id}}(other : {{other_klass}})
{{other_klass}}.new(self) {{op.id}} other
end
{% end %}
{% end %}
# :nodoc:
def unsafe_div(other : BigInt)
BigInt.new(self) / other
end
# :nodoc:
def unsafe_mod(other : BigInt)
BigInt.new(self) % other
end
@ -22,6 +30,7 @@ require "big_float"
end
{% end %}
# :nodoc:
struct BigInt
{% for op in ["+", "-", "*", "%", "/"] %}
def {{op.id}}(other : Float::Primitive)
@ -36,5 +45,4 @@ struct BigInt
def unsafe_shr(other : Int::All)
BigInt.new(self) ** other
end
end

27
src/lib/math/coef_binomial.cr

@ -0,0 +1,27 @@
# :nodoc:
require "big_int"
require "./factorial"
module Math
extend self
{% for num_type in [Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, BigInt] %}
# :nodoc:
include Math::Factorial({{num_type}})
{% end %}
# computes the binomial coefficient of (n, k)
def coef_binomial(n : Int, k : Int)
return 0 if n < 0 || k < 0 || n < k
# puts "n=#{n},k=#{k},n-k=#{n - k}, factorial(#{n})=#{factorial(n)}, (factorial(#{n}) * factorial(#{n - k}))=#{(factorial(k) * factorial(n - k))}"
return factorial(n) / (factorial(k) * factorial(n - k))
end
# Computes the Binomial distributions of *success* among *tries* given a *probability* of success.
#
# NOTE if no named parameters are used, then it will try to use the unamed parameters (tries, success, probability).
def binomial_distribution(tries : Int, success : Int, probability : Number)
Stats::BinomialDistribution(typeof(tries), typeof(probability)).new(n: tries, p: probability).distribute(success)
end
end

2
src/stats/math/exceptions.cr → src/lib/math/exceptions.cr

@ -1,5 +1,7 @@
module Math
# :nodoc:
class SuperiorityError < Exception; end
# :nodoc:
class DomainError < Exception; end
end

3
src/stats/math/factorial.cr → src/lib/math/factorial.cr

@ -1,5 +1,8 @@
module Math
# A factorial(N) = 1x2x3x...xN
module Factorial(U)
extend self
def factorial(n : U)
raise Math::DomainError.new "The argument must be a natural (out of domain -- factorial)" if n < 0
return U.new(1) if n == 0

0
src/lib/math/numeric_value.cr

20
src/lib/normale_distribution.cr

@ -0,0 +1,20 @@
require "./normale_distribution/persistant"
module Stats::NormaleDistribution
# Gives the probability of [ min; max ] for a normal distribution (*standard_deviation*)
def between(standard_deviation : Number, esperance : Number, min : Number, max : Number)
Stats::NormaleDistribution::Persistant(typeof(standard_deviation), typeof(esperance)).new(standard_deviation: standard_deviation, esperance: esperance).between min, max
end
# Gives the probability of [ min; +inf [ for a normal distribution (*standard_deviation*)
def greater_than(standard_deviation : Number, esperance : Number, min : Number)
Stats::NormaleDistribution::Persistant(typeof(standard_deviation), typeof(esperance)).new(standard_deviation: standard_deviation, esperance: esperance).greater_than min
end
# Gives the probability of ] -inf; max ] for a normal distribution (*standard_deviation*)
def less_than(standard_deviation : Number, esperance : Number, max : Number)
Stats::NormaleDistribution::Persistant(typeof(standard_deviation), typeof(esperance)).new(standard_deviation: standard_deviation, esperance: esperance).less_than max
end
extend self
end

33
src/lib/normale_distribution/persistant.cr

@ -0,0 +1,33 @@
class Stats::NormaleDistribution::Persistant(D, E)
property standard_deviation : D
property esperance : E
# Create a new normale distribution
def initialize(@standard_deviation = 1.0, @esperance = 0.0)
raise ArgumentError.new "standard_deviation must be > 0" unless @standard_deviation > 0.0
end
# Gives the probability of [ min; +inf [
def greater_than(min : Number)
1.0 - repartition(min)
end
# Gives the probability of ] -inf; max ]
def less_than(max : Number)
repartition max
end
# Gives the probability of [ min; max ]
def between(min : Number, max : Number)
repartition(max) - repartition(min)
end
# private def density(t : Number::All)
# 1.0 / (standard_deviation * (2 * Math::PI) ** 0.5) * Math::exp((t - esperance) / (2 * standard_deviation))
# end
private def repartition(t : Number)
erf = (t - esperance) / (standard_deviation * 2.0**0.5)
0.5 * (1.0 + Math.erf(erf))
end
end

7
src/stats.cr

@ -1,8 +1,5 @@
# require "big_int"
# require "big_float"
require "./stats/*"
require "./stats/math/*"
module Stats
# TODO Put your code here
end
require "./stats/*"
require "./lib/*"

21
src/stats/math/coef_binomial.cr

@ -1,21 +0,0 @@
require "./factorial"
require "big_int"
module Math
{% for num_type in [Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, BigInt] %}
include Math::Factorial({{num_type}})
{% end %}
extend self
def coef_binomial(n : Int::All, k : Int::All)
return 0 if n < 0 || k < 0 || n < k
# puts "n=#{n},k=#{k},n-k=#{n - k}, factorial(#{n})=#{factorial(n)}, (factorial(#{n}) * factorial(#{n - k}))=#{(factorial(k) * factorial(n - k))}"
return factorial(n) / (factorial(k) * factorial(n - k))
end
# @note if no named parameters are used, then it will try to use the unamed parameters (tries, success, probability)
def binomial_distribution(tries : Int::All, success : Int::All, probability : Number::All)
BinomialDistribution.new(n: tries, p: probability).distribute(success)
end
end

13
src/stats/math/numeric_value.cr

@ -1,13 +0,0 @@
abstract struct Int
alias All = Int::Primitive | BigInt
end
require "big_float"
abstract struct Float
alias All = Float::Primitive | BigFloat # | BigRational
end
abstract struct Number
alias All = Int::All | Float::All
end

17
src/stats/normale_distribution.cr

@ -1,17 +0,0 @@
require "./normale_distribution/persistant"
module NormaleDistribution
def between(standard_deviation : Number::All, esperance : Number::All, min : Number::All, max : Number::All)
NormaleDistribution::Persistant.new(standard_deviation: standard_deviation, esperance: esperance).between min, max
end
def greater_than(standard_deviation : Number::All, esperance : Number::All, min : Number::All)
NormaleDistribution::Persistant.new(standard_deviation: standard_deviation, esperance: esperance).greater_than min
end
def less_than(standard_deviation : Number::All, esperance : Number::All, max : Number::All)
NormaleDistribution::Persistant.new(standard_deviation: standard_deviation, esperance: esperance).less_than max
end
extend self
end

34
src/stats/normale_distribution/persistant.cr

@ -1,34 +0,0 @@
module NormaleDistribution
class Persistant
getter standard_deviation, esperance
setter standard_deviation, esperance
@standard_deviation : Number::All
@esperance : Number::All
def initialize(@standard_deviation = 1.0, @esperance = 0.0)
raise ArgumentError.new "standard_deviation must be > 0" unless @standard_deviation > 0.0
end
def greater_than(min : Number::All)
1.0 - repartition(min)
end
def less_than(max : Number::All)
repartition max
end
def between(min : Number::All, max : Number::All)
repartition(max) - repartition(min)
end
private def density(t : Number::All)
# 1.0 / (standard_deviation * (2 * Math::PI) ** 0.5) * Math::exp((t - esperance) / (2 * standard_deviation)))
end
private def repartition(t : Number::All)
erf = (t - esperance) / (standard_deviation * 2.0**0.5)
0.5 * (1.0 + Math.erf(erf))
end
end
end
Loading…
Cancel
Save