Class: RationalChoice::Dimension
- Inherits:
-
Object
- Object
- RationalChoice::Dimension
- Defined in:
- lib/rational_choice.rb
Overview
Represents a fuzzy choice on a single dimension (one real number)
Instance Method Summary collapse
-
#choose(value) ⇒ Boolean
Evaluate a value against the given false and true bound.
-
#fuzzy?(value) ⇒ Boolean
Tells whether the evaluation will use the probabilities or not (whether the given value is within the range where probability evaluation will take place).
-
#initialize(false_at_or_below:, true_at_or_above:, random: Random.new) ⇒ Dimension
constructor
Initializes a new Dimension to evaluate values.
Constructor Details
#initialize(false_at_or_below:, true_at_or_above:, random: Random.new) ⇒ Dimension
Initializes a new Dimension to evaluate values
20 21 22 23 24 25 26 |
# File 'lib/rational_choice.rb', line 20 def initialize(false_at_or_below:, true_at_or_above:, random: Random.new) raise DomainError, "Bounds were the same at #{false_at_or_below}" if false_at_or_below == true_at_or_above @random = random @lower, @upper = [false_at_or_below, true_at_or_above].sort @flip_sign = [@lower, @upper].sort != [false_at_or_below, true_at_or_above] end |
Instance Method Details
#choose(value) ⇒ Boolean
Evaluate a value against the given false and true bound.
If the value is less than or equal to the false bound, the method will return ‘false`. If the value is larger than or equal to the true bound, the method will return ’true’.
If the value is between the two bounds, the method will first determine the probability of the value being true, based on a linear interpolation. For example:
d = Dimension.new(false_at_or_below: 0, true_at_or_above: 1)
d.choose(0) # => false
d.choose(1) # => true
d.choose(0.5) #=> will be `true` in 50% of the cases (probability of 0.5)
d.choose(0.1) #=> will be `true` in 10% of the cases (probability of 0.1)
Primary use is for things like load balancing. Imagine you have a server handling 14 connections, and you know that it can take about 20 maximum. When you decide whether to send the connection number 17 to it, you want to take a little margin and only send that connection sometimes, to balance the choices - so you want to use a softer bound (a bit of a fuzzy logic).
# 10 connactions is doable, 20 connections means contention
will_accept_connection = Dimension.new(false_at_or_below: 20, true_at_or_above: 10)
will_accept_connection.choose(server.current_connection_count + 1) # will give you a fuzzy choice
54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/rational_choice.rb', line 54 def choose(value) choice = if fuzzy?(value) # Interpolate the probability of the value being true delta = @upper.to_f - @lower.to_f v = (value - @lower).to_f t = (v / delta) @random.rand < t else # just seen where it is (below or above) value >= @upper end choice ^ @flip_sign end |
#fuzzy?(value) ⇒ Boolean
Tells whether the evaluation will use the probabilities or not (whether the given value is within the range where probability evaluation will take place).
73 74 75 |
# File 'lib/rational_choice.rb', line 73 def fuzzy?(value) value > @lower && value < @upper end |