---
title: "Getting Started with rfsrs"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting Started with rfsrs}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

## Introduction

**rfsrs** provides R bindings for the FSRS (Free Spaced Repetition Scheduler) algorithm. FSRS is a modern spaced repetition algorithm that models human memory more accurately than traditional algorithms like SM-2.

```{r setup}
library(rfsrs)
```

## Understanding FSRS

### The Memory Model

FSRS models memory using two key variables:

1. **Stability (S)**: Represents how long a memory will last. Higher stability means slower forgetting. Specifically, stability is the number of days until retrievability drops to 90%.

2. **Difficulty (D)**: Represents how hard the material is to learn. Ranges from 1-10. Higher difficulty means stability grows more slowly with each review.

### Retrievability

Retrievability is the probability that you can recall a memory at a given time.

```{r forgetting-curve, fig.width=7, fig.height=5}
# Visualize the forgetting curve for different stability values
stability_values <- c(1, 5, 10, 30)
days <- 0:60

# Simple base R plot
plot(NULL, xlim = c(0, 60), ylim = c(0, 1),
     xlab = "Days since last review", ylab = "Retrievability",
     main = "Forgetting Curves for Different Stability Values")
colors <- c("red", "orange", "blue", "green")
for (i in seq_along(stability_values)) {
  s <- stability_values[i]
  r <- sapply(days, function(d) fsrs_recall_probability(s, d))
  lines(days, r, col = colors[i], lwd = 2)
}
legend("topright", legend = paste("S =", stability_values, "days"), 
       col = colors, lwd = 2)
abline(h = 0.9, lty = 2, col = "gray")
```

## Basic Usage

### Creating a New Card

When you first learn a card, you create an initial memory state based on your first rating:

```{r initial-state}
# Rating scale: 1=Again, 2=Hard, 3=Good, 4=Easy
state <- fsrs_new_card_state(rating = 3)  # First review, rated "Good"
print(state)
```

The initial stability depends on your rating:

```{r compare-initial}
ratings <- 1:4
rating_names <- c("Again", "Hard", "Good", "Easy")

for (i in ratings) {
  s <- fsrs_new_card_state(rating = i)
  cat(sprintf("%s (rating=%d): stability=%.2f, difficulty=%.2f\n",
              rating_names[i], i, s$stability, s$difficulty))
}
```

### Checking Retrievability

After a review, you can check how well you'll remember the card over time:

```{r check-retrievability}
state <- fsrs_new_card_state(rating = 3)

cat("Retrievability after:\n")
for (days in c(1, 3, 7, 14, 30)) {
  r <- fsrs_recall_probability(state$stability, elapsed_days = days)
  cat(sprintf("  %2d days: %.1f%%\n", days, r * 100))
}
```

### Getting the Next Interval

FSRS calculates the optimal interval for your next review based on desired retention:

```{r next-interval}
state <- fsrs_new_card_state(rating = 3)

# Get interval for 90% desired retention (default)
interval_90 <- fsrs_interval(state$stability, desired_retention = 0.9)
cat(sprintf("Interval for 90%% retention: %.1f days\n", interval_90))

# Get interval for 85% desired retention (fewer reviews)
interval_85 <- fsrs_interval(state$stability, desired_retention = 0.85)
cat(sprintf("Interval for 85%% retention: %.1f days\n", interval_85))

# Get interval for 95% desired retention (more reviews)
interval_95 <- fsrs_interval(state$stability, desired_retention = 0.95)
cat(sprintf("Interval for 95%% retention: %.1f days\n", interval_95))
```

### Simulating a Review

After reviewing a card, update the memory state:

```{r next-state}
# Initial state
state <- fsrs_new_card_state(rating = 3)
cat(sprintf("Initial: stability=%.2f\n", state$stability))

# Review after 2 days, rate "Good"
state <- fsrs_next_memory_state(
  stability = state$stability,
  difficulty = state$difficulty,
  elapsed_days = 2,
  rating = 3
)
cat(sprintf("After review 1: stability=%.2f\n", state$stability))

# Review after 5 days, rate "Good"
state <- fsrs_next_memory_state(
  stability = state$stability,
  difficulty = state$difficulty,
  elapsed_days = 5,
  rating = 3
)
cat(sprintf("After review 2: stability=%.2f\n", state$stability))
```

## Simulating Long-term Learning

Let's simulate learning a card over many reviews:

```{r simulate-learning}
simulate_learning <- function(n_reviews = 10, rating = 3, desired_retention = 0.9) {
  state <- fsrs_new_card_state(rating = rating)
  
  results <- data.frame(
    review = 0,
    day = 0,
    stability = state$stability,
    difficulty = state$difficulty,
    interval = NA
  )
  
  current_day <- 0
  
  for (i in 1:n_reviews) {
    interval <- fsrs_interval(state$stability, desired_retention)
    current_day <- current_day + interval
    state <- fsrs_next_memory_state(state$stability, state$difficulty, interval, rating,
                                       desired_retention)
    
    results <- rbind(results, data.frame(
      review = i,
      day = current_day,
      stability = state$stability,
      difficulty = state$difficulty,
      interval = interval
    ))
  }
  
  return(results)
}

# Simulate 10 reviews, always rating "Good"
learning <- simulate_learning(n_reviews = 10, rating = 3)
print(learning)
```

```{r plot-learning, fig.width=7, fig.height=5}
# Simulate a realistic learner who sometimes struggles
simulate_realistic <- function(ratings, desired_retention = 0.9) {
  state <- fsrs_new_card_state(rating = ratings[1])

  results <- data.frame(
    review = 0,
    day = 0,
    stability = state$stability,
    difficulty = state$difficulty,
    interval = NA,
    rating = ratings[1]
  )

  current_day <- 0

  for (i in seq_along(ratings)[-1]) {
    interval <- fsrs_interval(state$stability, desired_retention)
    current_day <- current_day + interval
    state <- fsrs_next_memory_state(state$stability, state$difficulty, interval,
                                    ratings[i], desired_retention)

    results <- rbind(results, data.frame(
      review = i - 1,
      day = current_day,
      stability = state$stability,
      difficulty = state$difficulty,
      interval = interval,
      rating = ratings[i]
    ))
  }

  results
}

# Always "Good" (idealized) vs. a realistic mix of ratings
ideal <- simulate_learning(n_reviews = 10, rating = 3)
realistic <- simulate_realistic(c(3, 2, 3, 1, 3, 3, 2, 3, 3, 3, 3))

# Log-scale plot comparing both scenarios
plot(ideal$review, ideal$stability, type = "b", pch = 19, log = "y",
     xlab = "Review Number", ylab = "Stability (days, log scale)",
     main = "Stability Growth Over Reviews",
     ylim = range(c(realistic$stability, ideal$stability)))
lines(realistic$review, realistic$stability, type = "b", pch = 17, col = "steelblue")
legend("topleft", legend = c("Always Good", "Mixed ratings"),
       pch = c(19, 17), col = c("black", "steelblue"), lty = 1)
grid()
```

## FSRS Parameters

FSRS uses 21 parameters that control the algorithm's behavior:

```{r parameters}
params <- fsrs_parameters()
cat("FSRS-6 default parameters (", length(params), " values):\n", sep = "")
print(round(params, 4))
```

## Summary

Key functions:

| Function | Description |
|----------|-------------|
| `fsrs_parameters()` | Get the 21 default FSRS-6 parameters |
| `fsrs_new_card_state(rating)` | Create initial memory state for a new card |
| `fsrs_next_memory_state(stability, difficulty, elapsed_days, rating)` | Calculate next state after review |
| `fsrs_interval(stability, desired_retention)` | Get optimal interval for desired retention |
| `fsrs_recall_probability(stability, elapsed_days)` | Calculate probability of recall |

For more information, see:

- [ABC of FSRS](https://github.com/open-spaced-repetition/fsrs4anki/wiki/ABC-of-FSRS)
- [fsrs-rs documentation](https://github.com/open-spaced-repetition/fsrs-rs)
