Skip to content

Instantly share code, notes, and snippets.

@ytti
Created September 23, 2016 12:45
Show Gist options
  • Save ytti/d7065275a638b160507a5f1b9dae7061 to your computer and use it in GitHub Desktop.
Save ytti/d7065275a638b160507a5f1b9dae7061 to your computer and use it in GitHub Desktop.
Monte Carlo simulation on when two networks or more networks fail together and for how many minutes (how robust does OOB network need to be, to have reasonable probability that both networks are not down at the same time)
#!/usr/bin/env ruby
module NetMonte
STANDARD_DEVIATION = 2.5
MINUTES = 365*24*60
class Simulate
def initialize years, *networks
years.times do |year|
nets = init_networks networks
roulette year, nets
end
end
private
def roulette year, nets
MINUTES.times do |minute|
nets.each do |net|
net.run minute
end
if nets.all? { |net| net.down }
puts "outage at year #{year}, minute #{minute}"
end
end
end
def init_networks networks
nets = []
networks.each do |net|
outage_count = RandomGaussian.new net[:outage_count], STANDARD_DEVIATION
outage_length = RandomGaussian.new net[:outage_length], STANDARD_DEVIATION
nets << Network.new(outage_count.rand, outage_length)
end
nets
end
end
class Network
attr_reader :down
def initialize outage_count, outage_length
@down = false
@outage_end = 0
@outage_probability = (1 / ((outage_count/365)/1440)).to_i
@outage_length = outage_length
end
def run minute
if @down and minute > @outage_end
@down = false
end
if rand(@outage_probability) == 42
@down = true
@outage_end = minute + @outage_length.rand
end
end
end
#stole from SE
class RandomGaussian
def initialize(mean = 0.0, sd = 1.0, rng = lambda { Kernel.rand })
@mean, @sd, @rng = mean, sd, rng
@compute_next_pair = false
end
def rand
if (@compute_next_pair = !@compute_next_pair)
# Compute a pair of random values with normal distribution.
# See http://en.wikipedia.org/wiki/Box-Muller_transform
theta = 2 * Math::PI * @rng.call
scale = @sd * Math.sqrt(-2 * Math.log(1 - @rng.call))
@g1 = @mean + scale * Math.sin(theta)
@g0 = @mean + scale * Math.cos(theta)
else
@g1
end
end
end
end
begin
if __FILE__ == $0
netA = { outage_count: 3.0, outage_length: 180.0 }
netO = { outage_count: 5.0, outage_length: 60.0 }
NetMonte::Simulate.new 10000, netA, netO
binding.pry
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment