r-fsrs: R bindings for the FSRS algorithm

As someone who uses Anki extensively for medical studies, I’ve always been fascinated by the algorithms that power spaced repetition. When the FSRS (Free Spaced Repetition Scheduler) algorithm emerged as a more accurate alternative to Anki’s traditional SM-2, I wanted to bring its power to the R ecosystem for research and analysis.

The result is rfsrs — R bindings for the fsrs-rs Rust library, now available on r-universe.

Install it now:
install.packages("rfsrs", repos = "https://chrislongros.r-universe.dev")

What is FSRS?

FSRS is a modern spaced repetition algorithm developed by Jarrett Ye that models memory more accurately than traditional algorithms. It’s based on the DSR (Difficulty, Stability, Retrievability) model of memory:

  • Stability — How long a memory will last (in days) before dropping to 90% retrievability
  • Difficulty — How hard the material is to learn (affects stability growth)
  • Retrievability — The probability of recalling the memory at any given time

FSRS-6, the latest version, uses 21 optimizable parameters that can be trained on your personal review history to predict optimal review intervals with remarkable accuracy.

The Rating Scale

FSRS uses a simple 4-point rating scale after each review:

1
Again
Blackout
2
Hard
Struggled
3
Good
Correct
4
Easy
Effortless

Why Rust + R?

The reference implementation of FSRS is written in Rust (fsrs-rs), which provides excellent performance and memory safety. Rather than rewriting the algorithm in R, I used rextendr to create native R bindings to the Rust library.

This approach offers several advantages:

  • Performance — Native Rust speed for computationally intensive operations
  • Correctness — Uses the official, well-tested implementation
  • Maintainability — Updates to fsrs-rs can be easily incorporated
  • Type Safety — Rust’s compiler catches errors at build time

Architecture

Here’s how rfsrs connects R to the Rust library:

rfsrs Architecture
R Layer
fsrs_default_parameters() fsrs_initial_state() fsrs_next_state() fsrs_retrievability()
rextendr Bridge
R → Rust
Vectors → Vec, Lists → structs
Rust → R
f64 → numeric, structs → lists
Rust Layer (fsrs-rs)
Algorithm
FSRS-6, 21 params
MemoryState
stability, difficulty
Functions
next_states(), etc.

Usage Examples

Getting Started

library(rfsrs)

# Get the 21 default FSRS-6 parameters
params <- fsrs_default_parameters()

# Create initial memory state (rating: Good)
state <- fsrs_initial_state(rating = 3)
# $stability: 2.3065
# $difficulty: 2.118104

Tracking Memory Decay

# How well will you remember?
for (days in c(1, 7, 30, 90)) {
  r <- fsrs_retrievability(state$stability, days)
  cat(sprintf("Day %2d: %.1f%%\n", days, r * 100))
}
# Day  1: 95.3%
# Day  7: 76.4%
# Day 30: 49.7%
# Day 90: 26.5%
Note: Stability of 2.3 days means memory drops to 90% retrievability after 2.3 days. This increases with each successful review.

Use Cases for R

  • Research — Analyze spaced repetition data with R’s statistical tools
  • Visualization — Plot memory decay curves with ggplot2
  • Integration with ankiR — Combine with ankiR to analyze your Anki collection
  • Custom schedulers — Build spaced repetition apps in R/Shiny

Building Rust + R Packages

The rextendr workflow:

  1. Create package with usethis::create_package()
  2. Run rextendr::use_extendr()
  3. Write Rust with #[extendr] macros
  4. Run rextendr::document()
  5. Build and check
Windows builds: Cross-compiling Rust for Windows can be tricky. My r-universe builds work on Linux and macOS but fail on Windows. Windows users can install from source with Rust installed.

Resources

What’s Next

Future plans include parameter optimization (training on your review history), batch processing, and tighter ankiR integration.

If you’re interested in spaced repetition or memory research, give rfsrs a try. Feedback welcome!

, ,

Leave a comment

Discover more from /root

Subscribe now to keep reading and get access to the full archive.

Continue reading