Created
September 23, 2016 12:45
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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