Class: WeightedListRank::Strategies::Exponential
- Inherits:
-
WeightedListRank::Strategy
- Object
- WeightedListRank::Strategy
- WeightedListRank::Strategies::Exponential
- Defined in:
- lib/weighted_list_rank/strategies/exponential.rb
Instance Attribute Summary collapse
-
#average_list_length ⇒ Object
readonly
Returns the value of attribute average_list_length.
-
#bonus_pool_percentage ⇒ Object
readonly
Returns the value of attribute bonus_pool_percentage.
-
#exponent ⇒ Object
readonly
Returns the value of attribute exponent.
-
#include_unranked_items ⇒ Object
readonly
Returns the value of attribute include_unranked_items.
-
#warn_on_invalid_position ⇒ Object
readonly
Returns the value of attribute warn_on_invalid_position.
Instance Method Summary collapse
-
#calculate_score(list, item) ⇒ Float
Calculates the score of a single item within a list based on its rank position, the total number of items, and the list's weight, using an exponential formula.
-
#calculate_scores(list) ⇒ Array<Float>
Calculates the scores for every item in a list in one pass.
-
#initialize(exponent: 1.5, bonus_pool_percentage: 1.0, average_list_length: nil, include_unranked_items: false, warn_on_invalid_position: false) ⇒ Exponential
constructor
Initializes the Exponential strategy with optional parameters for exponent, bonus pool percentage, average list length, and whether to include unranked items in the bonus pool.
Constructor Details
#initialize(exponent: 1.5, bonus_pool_percentage: 1.0, average_list_length: nil, include_unranked_items: false, warn_on_invalid_position: false) ⇒ Exponential
Initializes the Exponential strategy with optional parameters for exponent, bonus pool percentage, average list length, and whether to include unranked items in the bonus pool.
defaults to 1.0 (100%). defaults to nil. defaults to false for backward compatibility. position exceeds the number of items in the list. Such positions are always clamped to the last position; this only controls whether that is reported. Defaults to false, so scoring is silent.
20 21 22 23 24 25 26 27 |
# File 'lib/weighted_list_rank/strategies/exponential.rb', line 20 def initialize(exponent: 1.5, bonus_pool_percentage: 1.0, average_list_length: nil, include_unranked_items: false, warn_on_invalid_position: false) @exponent = exponent @bonus_pool_percentage = bonus_pool_percentage @average_list_length = average_list_length @include_unranked_items = include_unranked_items @warn_on_invalid_position = warn_on_invalid_position end |
Instance Attribute Details
#average_list_length ⇒ Object (readonly)
Returns the value of attribute average_list_length.
4 5 6 |
# File 'lib/weighted_list_rank/strategies/exponential.rb', line 4 def average_list_length @average_list_length end |
#bonus_pool_percentage ⇒ Object (readonly)
Returns the value of attribute bonus_pool_percentage.
4 5 6 |
# File 'lib/weighted_list_rank/strategies/exponential.rb', line 4 def bonus_pool_percentage @bonus_pool_percentage end |
#exponent ⇒ Object (readonly)
Returns the value of attribute exponent.
4 5 6 |
# File 'lib/weighted_list_rank/strategies/exponential.rb', line 4 def exponent @exponent end |
#include_unranked_items ⇒ Object (readonly)
Returns the value of attribute include_unranked_items.
4 5 6 |
# File 'lib/weighted_list_rank/strategies/exponential.rb', line 4 def include_unranked_items @include_unranked_items end |
#warn_on_invalid_position ⇒ Object (readonly)
Returns the value of attribute warn_on_invalid_position.
4 5 6 |
# File 'lib/weighted_list_rank/strategies/exponential.rb', line 4 def warn_on_invalid_position @warn_on_invalid_position end |
Instance Method Details
#calculate_score(list, item) ⇒ Float
Calculates the score of a single item within a list based on its rank position, the total number of items, and the list's weight, using an exponential formula. The bonus pool for score adjustments is determined by the specified bonus pool percentage of the list's total weight, adjusted by the average list length.
If include_unranked_items is true, unranked items will also receive a portion of the bonus pool.
Ranked items will receive an exponential bonus, while unranked items will split the remaining bonus pool evenly.
Scoring a whole list is cheaper through #calculate_scores, which shares the per-list work across items.
and the bonus pool percentage.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/weighted_list_rank/strategies/exponential.rb', line 90 def calculate_score(list, item) items = list.items total_items = items.count num_ranked_items = count_ranked(items) position = item.position if position.nil? score = list.weight if num_ranked_items.zero? && include_unranked_items score += adjusted_bonus_pool_for(list, total_items) / total_items end else if position > total_items report_invalid_positions(list, 1, total_items) position = total_items end exponential_factor = (total_items + 1 - position)**exponent score = list.weight + (exponential_factor / exponential_factor_sum(total_items)) * adjusted_bonus_pool_for(list, total_items) end floor(apply_penalty(score, item.score_penalty)) end |
#calculate_scores(list) ⇒ Array<Float>
Calculates the scores for every item in a list in one pass.
The number of ranked items, the adjusted bonus pool, and the total exponential factor are all constant across the list, so they are computed once here instead of once per item. Scoring a list is therefore linear in the number of items.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/weighted_list_rank/strategies/exponential.rb', line 38 def calculate_scores(list) items = list.items total_items = items.count return [] if total_items.zero? num_ranked_items = count_ranked(items) adjusted_bonus_pool = adjusted_bonus_pool_for(list, total_items) # Only lists containing ranked items need this, and it is the most # expensive value to produce, so it is computed on first use. total_exponential_factor = nil invalid_positions = 0 scores = items.map do |item| position = item.position if position.nil? score = list.weight if num_ranked_items.zero? && include_unranked_items score += adjusted_bonus_pool / total_items end else if position > total_items invalid_positions += 1 position = total_items end total_exponential_factor ||= exponential_factor_sum(total_items) exponential_factor = (total_items + 1 - position)**exponent score = list.weight + (exponential_factor / total_exponential_factor) * adjusted_bonus_pool end floor(apply_penalty(score, item.score_penalty)) end report_invalid_positions(list, invalid_positions, total_items) scores end |