FSRS Ruby - v6.0
A complete Ruby port of the FSRS (Free Spaced Repetition Scheduler) algorithm version 6.0. Claude Sonnet 4.5 by Antrhopic was used to generate this port.
Features
- ✅ FSRS v6.0 Algorithm: Exponential difficulty formula, linear damping, 21 parameters
- ✅ Short-term Learning: Minute-based scheduling with learning steps (e.g.,
['1m', '10m']) - ✅ State Machine: NEW → LEARNING → REVIEW ↔ RELEARNING
- ✅ Parameter Migration: Automatic migration from v4/v5 to v6 format
- ✅ Fuzzing: Optional interval randomization using Alea PRNG
- ✅ Strategy Pattern: Pluggable schedulers, learning steps, and seed strategies
- ✅ Cross-validated: Outputs match TypeScript implementation to 8 decimal places
Requirements
- Ruby >= 3.1.0
Installation
Add this line to your application's Gemfile:
gem 'fsrs_ruby'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install fsrs_ruby
Usage
Basic Example
require 'fsrs_ruby'
# Create FSRS instance with default parameters
fsrs = FsrsRuby.new
# Create a new card
card = FsrsRuby.create_empty_card(Time.now)
# Preview all possible ratings (Again, Hard, Good, Easy)
preview = fsrs.repeat(card, Time.now)
# Access results for each rating
good_result = preview[FsrsRuby::Rating::GOOD]
puts "If rated GOOD:"
puts " Next review: #{good_result.card.due}"
puts " Difficulty: #{good_result.card.difficulty}"
puts " Stability: #{good_result.card.stability}"
# Apply a specific rating
result = fsrs.next(card, Time.now, FsrsRuby::Rating::GOOD)
updated_card = result.card
Custom Parameters
fsrs = FsrsRuby.new(
request_retention: 0.9, # Target 90% retention
maximum_interval: 36500, # Max interval in days (~100 years)
enable_short_term: true, # Use minute-based learning steps
learning_steps: ['1m', '10m'], # Learning: 1 minute, then 10 minutes
relearning_steps: ['10m'], # Relearning: 10 minutes
enable_fuzz: false # Disable interval randomization
)
Getting Retrievability
# Get memory retention probability
retrievability = fsrs.get_retrievability(card, Time.now)
# => "95.23%"
# Get as decimal
retrievability = fsrs.get_retrievability(card, Time.now, format: false)
# => 0.9523
Rollback and Forget
# Rollback a review
previous_card = fsrs.rollback(updated_card, review_log)
# Reset card to NEW state
forgotten = fsrs.forget(card, Time.now, reset_count: true)
Custom Strategies
# Custom seed strategy
fsrs.use_strategy(:seed, ->(scheduler) {
"#{scheduler.current.id}_#{scheduler.current.reps}"
})
# Custom learning steps strategy
fsrs.use_strategy(:learning_steps, ->(params, state, cur_step) {
# Return custom step logic
{}
})
Algorithm Overview
State Transitions
NEW → LEARNING → REVIEW ↔ RELEARNING
- NEW: Card never reviewed
- LEARNING: Initial learning phase with short intervals
- REVIEW: Long-term review phase
- RELEARNING: Re-learning after forgetting (lapse)
Ratings
- Again (1): Complete failure, restart learning
- Hard (2): Difficult to recall
- Good (3): Recalled correctly with effort
- Easy (4): Recalled easily
Key Formulas (v6.0)
Initial Difficulty (Exponential):
D₀(G) = w[4] - exp((G-1) × w[5]) + 1
Next Difficulty (with Linear Damping):
Δd = -w[6] × (G - 3)
D' = D + linear_damping(Δd, D)
linear_damping(Δd, D) = (Δd × (10 - D)) / 9
Forgetting Curve:
R(t,S) = (1 + FACTOR × t / S)^DECAY
where: decay = -w[20], factor = exp(ln(0.9)/decay) - 1
Development
After checking out the repo, run:
$ bundle install
$ bundle exec rake spec
Cross-Validation
This implementation has been cross-validated against the TypeScript FSRS v6 implementation. All core formulas match to 8 decimal places.
See VERIFICATION_REPORT.md for detailed verification results.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/ondrejrohon/fsrs_ruby.
Please read CONTRIBUTING.md for details on how to contribute.
This project is intended to be a safe, welcoming space for collaboration. Contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Credits
This gem is a Ruby port of the TypeScript FSRS v6.0 implementation, developed with AI assistance and thoroughly cross-validated.
The FSRS algorithm was created by Jarrett Ye and the open-spaced-repetition community.
Verification
This implementation has been cross-validated against the TypeScript version with:
- ✅ 125 passing tests
- ✅ 89.87% code coverage
- ✅ Algorithm accuracy to 8 decimal places
- ✅ All known issues fixed and validated