Skip to content

Instantly share code, notes, and snippets.

@shedd
Created October 1, 2011 10:44
Show Gist options
  • Save shedd/1255865 to your computer and use it in GitHub Desktop.
Save shedd/1255865 to your computer and use it in GitHub Desktop.
Fun with Probability
# to run this file:
# gem install rspec
# rspec prob_spec.rb
class Integer
def factorial
self.downto(1).inject(:*)
end
end
class Dice
attr_accessor :number_of_choices, :choice_labels, :probabilities, :sides
def initialize number_of_choices, choice_labels, probabilities
@number_of_choices = number_of_choices
@choice_labels = choice_labels
@probabilities = probabilities
@sides = Hash.new
raise "probability values do not add up to 1" unless probabilities.inject(:+) == 1
choice_labels = [ choice_labels ] if choice_labels.class == String # convert to array if we're being passed a single side
choice_labels.each_with_index{ |choice, n| @sides.merge!( choice => probabilities[n] ) }
end
def method_missing(*args)
# args[0] is the method name called
if args.length == 2 and args[0] == :call and args[1].class == String
@sides[ args[1] ]
else
super
end
end
end
class Solve
attr_reader :dice
protected :dice
def initialize d
@dice = d
end
def prob_of_ordered_events events
events.inject(1){|product, e| product * @dice.sides[e] }.round(4)
end
def prob_of_unordered_events events
self.choose(events.size, events.count(events.last), nil) * prob_of_ordered_events(events)
end
def choose n, k, d
n.factorial / ( k.factorial * (n-k).factorial)
end
end
describe "Dice" do
context "in context to initializing class variables" do
it "should allow you to configure the number of sides for a dice, with each side having a label, and a unique probability" do
dice = Dice.new(2, ["heads","tails"], [0.5,0.5])
dice.number_of_choices.should == 2
dice.choice_labels.should == ["heads","tails"]
dice.("heads").should == 0.5
dice.("tails").should == 0.5
end
it "should fail if you give it probability values that do not add up to 1" do
expect { Dice.new(1,["heads"],[0.9]) }.should raise_error
end
it "should support dice with 1 side" do
dice = Dice.new(1,["heads"],[1.0])
dice.number_of_choices.should == 1
end
end
end
describe "Solve" do
it "should solve for the probability of a list of ordered events" do
four_sided_die = Dice.new(4, ["1","2","3","4"], [0.20,0.20,0.20,0.40])
Solve.new(four_sided_die).prob_of_ordered_events(["1","4","2"]).should == 0.016
end
it "should solve for the probability of a set of unordered events" do
two_sided_die = Dice.new(2,["heads","tails"],[0.5,0.5])
Solve.new(two_sided_die).prob_of_unordered_events(["tails","heads"]).should == 0.5
Solve.new(two_sided_die).prob_of_unordered_events(["heads","tails"]).should == 0.5
end
it "should solve for the probability of a choice of events" do
one_sided_die = Dice.new(1,"only side",[1.0])
#Given 3 Dice and 5 Buckets, how many ways are there to place the Dice in the Buckets
#Also known as k Choose n or 5 choose 3
Solve.new(one_sided_die).choose(5, 3, one_sided_die).should == 10
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment