An Elixir implementation of FSRS (Free Spaced Repetition Scheduler in Elixir)
A flexible spaced repetition scheduling implementation in Elixir. This library is designed to help you schedule reviews in an optimal way, taking into account card difficulty, stability, and user feedback. The code here demonstrates how to compute the next intervals for flashcards using advanced scheduling techniques, including fuzzing intervals to avoid predictable review dates.
This project implements a variant of the FSRS (Free Spaced Repetition Schedule) algorithm in Elixir. The code is intended for advanced spaced repetition systems, allowing dynamic interval calculation, difficulty tracking, state transitions, and fuzzing intervals to avoid "review day clumping".
Key features:
If you want to include this functionality in your own Elixir application, you can integrate it as a local dependency or copy the modules directly into your project. For a typical Elixir project:
Add the project as a dependency in your mix.exs (if you have a private git repository or local path, adjust accordingly):
def deps do
[
{:ex_fsrs, "~> 0.1.0", git: "https://github.com/open-spaced-repetition/ex_fsrs"}
]
end
Fetch and compile dependencies:
mix deps.get
mix compile
Below is a quick example demonstrating how you might use the core ExFsrs module to process a review for a given card:
# Create a new card
card = ExFsrs.new(state: :learning, step: 0)
# Review the card with a rating
{updated_card, review_log} = ExFsrs.review_card(card, :good)
# Or use the scheduler directly with custom parameters
scheduler = ExFsrs.Scheduler.new(
parameters: [0.40255, 1.18385, 3.173, 15.69105, 7.1949, 0.5345, 1.4604, 0.0046, 1.54575, 0.1192, 1.01925, 1.9395, 0.11, 0.29605, 2.2698, 0.2315, 2.9898, 0.51655, 0.6621],
desired_retention: 0.9,
learning_steps: [1.0, 10.0],
relearning_steps: [10.0],
maximum_interval: 36500,
enable_fuzzing: true
)
{updated_card, review_log} = ExFsrs.Scheduler.review_card(scheduler, card, :good)
What happens under the hood?
Card State Update
The card's state is updated based on the rating and current state (learning, review, or relearning).
Difficulty & Stability Calculation
The scheduler computes new difficulty and stability values based on the rating and time since last review.
Interval Computation
Based on the new difficulty, stability, and rating, the next review interval is calculated. If fuzzing is enabled, the interval may be slightly randomized.
Logging
A ReviewLog is created to track the review outcome, including the rating, review datetime, and updated card state.
The main module that provides the card struct and basic review functionality.
defmodule ExFsrs do
@type t :: %__MODULE__{
card_id: integer(),
state: :learning | :review | :relearning,
step: integer() | nil,
stability: float() | nil,
difficulty: float() | nil,
due: DateTime.t(),
last_review: DateTime.t() | nil
}
defstruct [
:card_id,
:state,
:step,
:stability,
:difficulty,
:due,
:last_review
]
end
Handles the core spaced repetition algorithm, including interval calculation and state transitions.
defmodule ExFsrs.Scheduler do
@type t :: %__MODULE__{
parameters: [float()],
desired_retention: float(),
learning_steps: [float()],
relearning_steps: [float()],
maximum_interval: integer(),
enable_fuzzing: boolean()
}
defstruct [
:parameters,
:desired_retention,
:learning_steps,
:relearning_steps,
:maximum_interval,
:enable_fuzzing
]
end
Tracks the outcome of a review, including the rating and updated card state.
defmodule ExFsrs.ReviewLog do
@type t :: %__MODULE__{
card: ExFsrs.t(),
rating: ExFsrs.rating(),
review_datetime: DateTime.t(),
review_duration: integer() | nil
}
defstruct [
:card,
:rating,
:review_datetime,
:review_duration
]
end
The library comes with a test suite to ensure functionality works as expected.
To run the entire test suite:
mix test
This will execute all tests, including unit tests for individual modules and integration tests.
You can also run specific test files:
mix test test/scheduler_test.exs
Or run tests with a specific tag:
mix test --only performance
For a more detailed demonstration of how the algorithm works with different card states and ratings, you can run the Complex test:
# Start an interactive Elixir shell with the project loaded
iex -S mix
# Load the complex test file
c("test/complex_test.exs")
# Run the test function
ExFsrsTest.Complex.run()
This will output detailed information about card state transitions, including:
The complex test is particularly useful for visualizing how the algorithm behaves under different conditions and can be a helpful educational tool for understanding the FSRS system.
Contributions are welcome! If you would like to fix bugs or add new features:
Please ensure you include tests where appropriate.
This project is available as open source under the terms of the MIT License. Feel free to use it, distribute it, and contribute.
Happy coding. If you have any questions or want to share how you're using this library, feel free to open an issue or pull request.
Elixir
100.0%
An Elixir implementation of FSRS (Free Spaced Repetition Scheduler in Elixir)
A flexible spaced repetition scheduling implementation in Elixir. This library is designed to help you schedule reviews in an optimal way, taking into account card difficulty, stability, and user feedback. The code here demonstrates how to compute the next intervals for flashcards using advanced scheduling techniques, including fuzzing intervals to avoid predictable review dates.
This project implements a variant of the FSRS (Free Spaced Repetition Schedule) algorithm in Elixir. The code is intended for advanced spaced repetition systems, allowing dynamic interval calculation, difficulty tracking, state transitions, and fuzzing intervals to avoid "review day clumping".
Key features:
If you want to include this functionality in your own Elixir application, you can integrate it as a local dependency or copy the modules directly into your project. For a typical Elixir project:
Add the project as a dependency in your mix.exs (if you have a private git repository or local path, adjust accordingly):
def deps do
[
{:ex_fsrs, "~> 0.1.0", git: "https://github.com/open-spaced-repetition/ex_fsrs"}
]
end
Fetch and compile dependencies:
mix deps.get
mix compile
Below is a quick example demonstrating how you might use the core ExFsrs module to process a review for a given card:
# Create a new card
card = ExFsrs.new(state: :learning, step: 0)
# Review the card with a rating
{updated_card, review_log} = ExFsrs.review_card(card, :good)
# Or use the scheduler directly with custom parameters
scheduler = ExFsrs.Scheduler.new(
parameters: [0.40255, 1.18385, 3.173, 15.69105, 7.1949, 0.5345, 1.4604, 0.0046, 1.54575, 0.1192, 1.01925, 1.9395, 0.11, 0.29605, 2.2698, 0.2315, 2.9898, 0.51655, 0.6621],
desired_retention: 0.9,
learning_steps: [1.0, 10.0],
relearning_steps: [10.0],
maximum_interval: 36500,
enable_fuzzing: true
)
{updated_card, review_log} = ExFsrs.Scheduler.review_card(scheduler, card, :good)
What happens under the hood?
Card State Update
The card's state is updated based on the rating and current state (learning, review, or relearning).
Difficulty & Stability Calculation
The scheduler computes new difficulty and stability values based on the rating and time since last review.
Interval Computation
Based on the new difficulty, stability, and rating, the next review interval is calculated. If fuzzing is enabled, the interval may be slightly randomized.
Logging
A ReviewLog is created to track the review outcome, including the rating, review datetime, and updated card state.
The main module that provides the card struct and basic review functionality.
defmodule ExFsrs do
@type t :: %__MODULE__{
card_id: integer(),
state: :learning | :review | :relearning,
step: integer() | nil,
stability: float() | nil,
difficulty: float() | nil,
due: DateTime.t(),
last_review: DateTime.t() | nil
}
defstruct [
:card_id,
:state,
:step,
:stability,
:difficulty,
:due,
:last_review
]
end
Handles the core spaced repetition algorithm, including interval calculation and state transitions.
defmodule ExFsrs.Scheduler do
@type t :: %__MODULE__{
parameters: [float()],
desired_retention: float(),
learning_steps: [float()],
relearning_steps: [float()],
maximum_interval: integer(),
enable_fuzzing: boolean()
}
defstruct [
:parameters,
:desired_retention,
:learning_steps,
:relearning_steps,
:maximum_interval,
:enable_fuzzing
]
end
Tracks the outcome of a review, including the rating and updated card state.
defmodule ExFsrs.ReviewLog do
@type t :: %__MODULE__{
card: ExFsrs.t(),
rating: ExFsrs.rating(),
review_datetime: DateTime.t(),
review_duration: integer() | nil
}
defstruct [
:card,
:rating,
:review_datetime,
:review_duration
]
end
The library comes with a test suite to ensure functionality works as expected.
To run the entire test suite:
mix test
This will execute all tests, including unit tests for individual modules and integration tests.
You can also run specific test files:
mix test test/scheduler_test.exs
Or run tests with a specific tag:
mix test --only performance
For a more detailed demonstration of how the algorithm works with different card states and ratings, you can run the Complex test:
# Start an interactive Elixir shell with the project loaded
iex -S mix
# Load the complex test file
c("test/complex_test.exs")
# Run the test function
ExFsrsTest.Complex.run()
This will output detailed information about card state transitions, including:
The complex test is particularly useful for visualizing how the algorithm behaves under different conditions and can be a helpful educational tool for understanding the FSRS system.
Contributions are welcome! If you would like to fix bugs or add new features:
Please ensure you include tests where appropriate.
This project is available as open source under the terms of the MIT License. Feel free to use it, distribute it, and contribute.
Happy coding. If you have any questions or want to share how you're using this library, feel free to open an issue or pull request.
Elixir
100.0%