Modifying old revlog ease factor values into FSRS difficulty

The old Auto Ease Factor addon had a function for rewriting the revlog ease factors as if they had been reviewed using the config enabled at that time. This was a dangerous operation that was only kind of undoable in that you could set your config back to what it was before and rewrite the revlog again.

The SM2 revlog rewrite code from Auto Ease Factor is like this:

Now that I’ve switched to using FSRS instead of my heavily customized SM2 scheduling, I’d like to make a similar function that would overwrite the factor values using the current FSRS settings as if those reviews had been done with my current FSRS settings.

Is this even possible? If so, what Anki backend functions will I need to use?

Here is the code employed in Anki Rust backend:

Why do you want to overwrite the D values in the old revlogs? The values don’t affect scheduling. Scheduling depends on the value of memory states in the cards table. These values in the cards table are automatically updated whenever you update the parameters as if you did all the reviews with the latest parameters.

I know. The reason is curiosity and vanity:

  • I’m curious as to what difficulty values different FSRS configs would give to my historical reviews
  • And because I’ve made a cool little graph to show the revlog in my card templates. It bugs me that the graph contains mixed values.

tiny_revlog_graph

anki/rslib/src/revlog/mod.rs at a6426bebe21ea1fe85f5cf31a711134b06447788 · ankitects/anki · GitHub

I think this isn’t what I need. The rust backend part where it sets the card.memory_state and then passes that card to log_scheduled_review, is what I’m looking for, I think.

If I understand the gist of the FSRS algorithm correctly, I need to calculate S, R and D for a historical review and then calculate the next S, R, D using the previous ones as input, right? I imagine the code I need is something like this:

def get_next_memory_state(
  stability,
  difficulty,
  elapsed_days,
  answer,
  fsrs_params,
):
  retrievability = calc_retrievability(stability, difficulty, fsrs_params, elapsed_days)
  new_stability, new_difficulty = calc_memory_state(stability, difficulty, retrievability, answer)
  return new_stability, new_difficulty

def calc_first_memory_state(answer, fsrs_params):
  ...
  return stability, difficulty


...


fsrs_params = col.decks.get...
sd_list = [calc_first_memory_state(all_card_revs[0].ease, fsrs_params)]

for i in len(all_card_revs):
  last_rev = all_card_revs[i]
  rev = all_card_revs[i + 1]
  stability, difficulty = sd_list[i]
  elapsed_days = calc_elapsed_days(last_rev, rev)
  new_stability, new_difficulty = get_next_memory_state(
    stability,
    difficulty,
    rev.ease,
    fsrs_params,
  )
  sd_list.append((new_stability, new_difficulty))