Module: FsrsRuby::ParameterUtils
- Defined in:
- lib/fsrs_ruby/parameters.rb
Class Method Summary collapse
-
.check_parameters(parameters) ⇒ Array<Numeric>
Check if parameters are valid.
-
.clip_parameters(parameters, num_relearning_steps, enable_short_term = true) ⇒ Array<Float>
Clip parameters to valid ranges.
-
.create_empty_card(now = nil) ⇒ Card
Create an empty card.
-
.generate_parameters(props = {}) ⇒ Parameters
Generate FSRS parameters from partial input.
-
.migrate_parameters(parameters = nil, num_relearning_steps = 0, enable_short_term = true) ⇒ Array<Float>
Migrate parameters from v4/v5 to v6 format.
Class Method Details
.check_parameters(parameters) ⇒ Array<Numeric>
Check if parameters are valid
36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/fsrs_ruby/parameters.rb', line 36 def self.check_parameters(parameters) invalid = parameters.find { |param| !param.is_a?(Numeric) || !param.finite? } if invalid raise ArgumentError, "Non-finite or NaN value in parameters: #{parameters}" elsif ![17, 19, 21].include?(parameters.length) raise ArgumentError, "Invalid parameter length: #{parameters.length}. Must be 17, 19 or 21 for FSRSv4, 5 and 6 respectively." end parameters end |
.clip_parameters(parameters, num_relearning_steps, enable_short_term = true) ⇒ Array<Float>
Clip parameters to valid ranges
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/fsrs_ruby/parameters.rb', line 10 def self.clip_parameters(parameters, num_relearning_steps, enable_short_term = true) w17_w18_ceiling = Constants::W17_W18_CEILING if [num_relearning_steps, 0].max > 1 # Calculate ceiling: w17 * w18 <= -[ln(w11) + ln(2^w13 - 1) + w14*0.3] / num_relearning_steps value = -( Math.log(parameters[11]) + Math.log(2.0**parameters[13] - 1.0) + parameters[14] * 0.3 ) / num_relearning_steps w17_w18_ceiling = Helpers.clamp(Helpers.round8(value), 0.01, 2.0) end clamp_ranges = Constants.clamp_parameters(w17_w18_ceiling, enable_short_term) clamp_ranges = clamp_ranges.slice(0, parameters.length) clamp_ranges.each_with_index.map do |(min, max), index| Helpers.clamp(parameters[index] || 0, min, max) end end |
.create_empty_card(now = nil) ⇒ Card
Create an empty card
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/fsrs_ruby/parameters.rb', line 111 def self.create_empty_card(now = nil) now ||= Time.now Card.new( due: now, stability: 0.0, difficulty: 0.0, elapsed_days: 0, scheduled_days: 0, learning_steps: 0, reps: 0, lapses: 0, state: State::NEW, last_review: nil ) end |
.generate_parameters(props = {}) ⇒ Parameters
Generate FSRS parameters from partial input
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/fsrs_ruby/parameters.rb', line 86 def self.generate_parameters(props = {}) learning_steps = props[:learning_steps] || Constants::DEFAULT_LEARNING_STEPS.dup relearning_steps = props[:relearning_steps] || Constants::DEFAULT_RELEARNING_STEPS.dup enable_short_term = props.key?(:enable_short_term) ? props[:enable_short_term] : Constants::DEFAULT_ENABLE_SHORT_TERM w = migrate_parameters( props[:w], relearning_steps.length, enable_short_term ) Parameters.new( request_retention: props[:request_retention] || Constants::DEFAULT_REQUEST_RETENTION, maximum_interval: props[:maximum_interval] || Constants::DEFAULT_MAXIMUM_INTERVAL, w: w, enable_fuzz: props.key?(:enable_fuzz) ? props[:enable_fuzz] : Constants::DEFAULT_ENABLE_FUZZ, enable_short_term: enable_short_term, learning_steps: learning_steps, relearning_steps: relearning_steps ) end |
.migrate_parameters(parameters = nil, num_relearning_steps = 0, enable_short_term = true) ⇒ Array<Float>
Migrate parameters from v4/v5 to v6 format
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/fsrs_ruby/parameters.rb', line 53 def self.migrate_parameters(parameters = nil, num_relearning_steps = 0, enable_short_term = true) return Constants::DEFAULT_WEIGHTS.dup if parameters.nil? case parameters.length when 21 # v6: Just clip clip_parameters(parameters.dup, num_relearning_steps, enable_short_term) when 19 # v5: Clip and append [0.0, FSRS5_DEFAULT_DECAY] warn '[FSRS-6] Auto fill w from 19 to 21 length' clipped = clip_parameters(parameters.dup, num_relearning_steps, enable_short_term) clipped + [0.0, Constants::FSRS5_DEFAULT_DECAY] when 17 # v4: Clip, transform w[4], w[5], w[6], then append [0.0, 0.0, 0.0, FSRS5_DEFAULT_DECAY] w = clip_parameters(parameters.dup, num_relearning_steps, enable_short_term) # Transform parameters for v6 w[4] = Helpers.round8(w[5] * 2.0 + w[4]) w[5] = Helpers.round8(Math.log(w[5] * 3.0 + 1.0) / 3.0) w[6] = Helpers.round8(w[6] + 0.5) warn '[FSRS-6] Auto fill w from 17 to 21 length' w + [0.0, 0.0, 0.0, Constants::FSRS5_DEFAULT_DECAY] else # Invalid length, use defaults warn '[FSRS] Invalid parameters length, using default parameters' Constants::DEFAULT_WEIGHTS.dup end end |