GithubHelp home page GithubHelp logo

open-spaced-repetition / fsrs4anki Goto Github PK

View Code? Open in Web Editor NEW
2.3K 25.0 123.0 65.21 MB

A modern Anki custom scheduling based on Free Spaced Repetition Scheduler algorithm

Home Page: https://github.com/open-spaced-repetition/fsrs4anki/wiki

License: MIT License

JavaScript 0.10% Jupyter Notebook 99.90%
anki-addon spaced-repetition-algorithm anki deep-learning memory spaced-repetition srs machine-learning optimal-control reinforcement-learning

fsrs4anki's Introduction

FSRS4Anki

FSRS4Anki

✨ A modern spaced-repetition scheduler for Anki based on the Free Spaced Repetition Scheduler algorithm

license release

Table of contents

Introduction

FSRS4Anki consists of two main parts: the scheduler and the optimizer.

  • The scheduler replaces Anki's built-in scheduler and schedules the cards according to the FSRS algorithm.
  • The optimizer uses machine learning to learn your memory patterns and finds parameters that best fit your review history. For details about the working of the optimizer, please read the mechanism of optimization.

For details about the FSRS algorithm, please read the algorithm. If you are interested, you can also read my papers:

FSRS4Anki Helper is an Anki add-on that complements the FSRS4Anki Scheduler. You can read about it here: https://github.com/open-spaced-repetition/fsrs4anki-helper

How to Get Started?

If you are using Anki v23.10 or newer, refer to this tutorial.

If you are using an older version of Anki, refer to this tutorial.

Note that setting up FSRS is much easier in Anki v23.10 or newer.

Add-on Compatibility

Some add-ons can cause conflicts with FSRS. As a general rule of thumb, if an add-on affects a card's intervals, it shouldn't be used with FSRS.

Add-on Compatible? Comment
Review Heatmap Yes ✅ Doesn't affect anything FSRS-related.
Advanced Browser Yes ✅ Please use the latest version.
Advanced Review Bottom Bar Yes ✅ Please use the latest version.
The KING of Button Add-ons Yes ✅ Please use the latest version.
Pass/Fail Yes ✅ Pass is the equivalent of Good, Fail is the equivalent of Again.
AJT Card Management Yes ✅ Compatible with Anki 23.12 and newer.
Incremental Reading v4.11.3 (unofficial clone) Unsure ❓ If you are using the standalone version of FSRS, it shows the interval given by Anki's built-in scheduler, not the custom scheduler. This add-on is technically compatible with built-in FSRS, but FSRS was not designed for incremental reading, and FSRS settings do not apply to IR cards because they work in a different way compared to other card types.
Delay siblings No ❌ Delay siblings will modify the intervals given by FSRS. However, the FSRS4Anki Helper add-on has a similar feature that works better with FSRS. Please use the FSRS4Anki Helper add-on instead.
Auto Ease Factor No ❌ The Ease Factor is no longer relevant when FSRS is enabled, therefore you won't benefit from using this add-on.
autoLapseNewInterval No ❌ The New Interval setting is no longer relevant when FSRS is enabled, therefore you won't benefit from using this add-on.
Straight Reward No ❌ The Ease Factor is no longer relevant when FSRS is enabled, therefore you won't benefit from using this add-on.

Let me know via issues if you want me to check compatibility between FSRS and some add-on.

Contribute

You can contribute to FSRS4Anki by beta testing, submitting code, or sharing your data. If you want to share your data with me, please fill out this form: https://forms.gle/KaojsBbhMCytaA7h8

Contributors

All Contributors

Expertium
Expertium

⚠️ 📖 🔣 🤔 🐛
user1823
user1823

⚠️ 📖 🔣 🤔 🐛
Christos Longros
Christos Longros

🔣 🖋

Stargazers over time

Star History Chart

fsrs4anki's People

Contributors

allcontributors[bot] avatar asukaminato0721 avatar dawrom avatar expertium avatar galantra avatar kieranlblack avatar l-m-sherlock avatar luc-mcgrady avatar mnastri avatar user1823 avatar volt2054 avatar wlckd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fsrs4anki's Issues

[BUG] Latest fsrs4anki helper error

Describe the bug
I updated the fsrs4anki helper to the latest version, and then I got an error.

To Reproduce
Steps to reproduce the behaviour:

  1. Updated fsrs4anki helper to the latest version
  2. updated an individual deck
  3. Tools -> Reschedule all cards
  4. error

Expected behaviour
Should update the entire collection.

Screenshots
image

Environment

  • Anki version: [e.g. 2.1.55]
  • OS: Window 10
  • Scheduler version: [v3.4.0]
  • Optimizer version: [v3.2.1]
  • Simulator version: [v3.3.2]

[Feature Request] Provide instruction for installing and running the optimizer locally

Which module is related to your feature request?
Optimizer

Is your feature request related to a problem? Please describe.

I'm more efficient and productive when doing things locally compared with doing remotely. In this case, I would prefer running the optimizer locally on my system instead of having to run it in Google Colab. Being able to run the optimizer on my local system would, to the very least, eliminate from having to upload the exported deck, changing the .apkg file name and the time zone every time. Also, I use Linux, so I guess that setting it up on Linux would be a bit easier.

Describe the solution you'd like

Describe alternatives you've considered

Additional context

[BUG] [FSRS4Anki v1.6.1 Optimizer] Optimized Default Difficulty is too low on large revlog

Describe the bug
After optimizing the parameters using fsrs4anki_optimizer on a large revlog, the default difficulty is too low

let defaultDifficulty = 1.1873;
let defaultStability = 3.6988;
let difficultyDecay = -0.9949;
let stabilityDecay = -0.1412;
let retrievabilityFactor = 1.2742;
let increaseFactor = 2.9295;
let lapsesBase = -0.062;

To Reproduce
Steps to reproduce the behavior:

  1. Download FSRS4Anki v1.6.1 Optimizer and import to Google Colab
  2. Upload a collection with large review history (about ~300k logs). See [REMOVED]
  3. Change settings to
# Here are some settings that you need to replace before running this optimizer.

filename = "collection.colpkg"
# If you upload deck file, replace it with your deck filename. E.g., ALL__Learning.apkg
# If you upload collection file, replace it with your colpgk filename. E.g., [email protected]

# Replace it with your timezone. I'm in China, so I use Asia/Shanghai.
timezone = 'America/Toronto'

# Replace it with your Anki's setting in Prefernces -> Scheduling.
next_day_starts_at = 8

# Replace it if you don't want the optimizer to use the review logs before a specific date.
revlog_start_date = "2006-10-05"
  1. Runtime -> Run all

Output:

Extract successfully!

revlog.csv saved!
100%|██████████| 24582/24582 [04:35<00:00, 89.13it/s] 
Trainset saved!

100%|██████████| 313064/313064 [00:49<00:00, 6335.75it/s] 
Tensorized!
train:   0%|          | 16/313064 [00:00<1:50:46, 47.10it/s]iteration: 1
f_s: [1.9995]
f_d: [4.9995]
s_w: [3.0005, -0.6995, -0.2005, 1.0005, -0.3005]
train:  10%|█         | 31323/313064 [03:43<38:44, 121.21it/s]iteration: 31307
f_s: [2.8145]
f_d: [4.2811]
s_w: [3.1621, -0.7659, -0.1151, 1.1874, -0.0596]
train:  20%|██        | 62628/313064 [07:27<33:40, 123.94it/s]iteration: 62613
f_s: [3.1593]
f_d: [3.7107]
s_w: [3.2328, -0.9031, -0.0954, 1.2932, -0.0553]
train:  30%|███       | 93934/313064 [11:09<26:09, 139.61it/s]iteration: 93919
f_s: [3.4398]
f_d: [3.2537]
s_w: [3.2627, -0.9976, -0.0962, 1.3511, -0.0815]
train:  40%|████      | 125244/313064 [14:49<21:28, 145.81it/s]iteration: 125225
f_s: [3.6134]
f_d: [2.9337]
s_w: [3.2254, -0.998, -0.1659, 1.3523, -0.0869]
train:  50%|█████     | 156550/313064 [18:27<18:03, 144.47it/s]iteration: 156531
f_s: [3.605]
f_d: [2.6452]
s_w: [3.1698, -0.9975, -0.1452, 1.339, -0.0917]
train:  60%|██████    | 187855/313064 [22:05<13:34, 153.73it/s]iteration: 187837
f_s: [3.6384]
f_d: [2.3413]
s_w: [3.1219, -0.9863, -0.0997, 1.3147, -0.0245]
train:  70%|███████   | 219161/313064 [25:38<09:30, 164.48it/s]iteration: 219143
f_s: [3.6706]
f_d: [2.0742]
s_w: [3.0706, -0.9885, -0.1018, 1.2922, -0.0602]
train:  80%|████████  | 250468/313064 [29:06<07:48, 133.49it/s]iteration: 250449
f_s: [3.7285]
f_d: [1.6587]
s_w: [3.0623, -0.9938, -0.1125, 1.317, -0.0961]
train:  90%|█████████ | 281776/313064 [32:33<03:31, 148.23it/s]iteration: 281755
f_s: [3.8183]
f_d: [1.3745]
s_w: [2.9781, -0.9904, -0.179, 1.2664, -0.0859]
train: 100%|██████████| 313064/313064 [35:58<00:00, 145.05it/s]iteration: 313061
f_s: [3.6984]
f_d: [1.1872]
s_w: [2.9299, -0.9943, -0.1408, 1.2746, -0.0626]

Training finished!

let defaultDifficulty = 1.1873;
let defaultStability = 3.6988;
let difficultyDecay = -0.9949;
let stabilityDecay = -0.1412;
let retrievabilityFactor = 1.2742;
let increaseFactor = 2.9295;
let lapsesBase = -0.062;

1:again, 2:hard, 3:good, 4:easy

first rating: 1
rating history: 1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
interval history: 0,1,2,3,5,8,13,20,30,45,65,93,132,184,252,343
difficulty history: 0,3.2,3.2,3.2,3.2,3.2,3.2,3.2,3.2,3.2,3.2,3.2,3.2,3.2,3.2,3.2

first rating: 2
rating history: 2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
interval history: 0,2,4,8,14,25,43,71,115,181,279,420,621,902,1290,1817
difficulty history: 0,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2

first rating: 3
rating history: 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
interval history: 0,4,10,25,56,119,240,460,845,1493,2551,4227,6812,10707,16451,24757
difficulty history: 0,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2

first rating: 4
rating history: 4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
interval history: 0,7,54,320,1547,6295,22147,68839,192501,491578,1160631,2559857,5319872,10492922,19763234,35730756
difficulty history: 0,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2

rating history: 3,3,3,2,3,4,3,3,1,3,3,3
interval history: 0,4,10,25,30,80,183,421,992,4,9,20,42
difficulty history: 0,1.2,1.2,1.2,1.7,1.7,0.7,0.7,0.7,1.4,1.4,1.4,1.4

Expected behavior
The default difficultly should not be as low as 1.1873

Environment

  • Optimizer version: v1.6.1

Additional context
I believe the issue has come from the commit 4185f3d

Change the learning rate from lr=1e-4 to lr=5e-4 might be too aggressive?

[BUG] Error when using optimizer 3.7.2

Describe the bug
An error occurs when optimizer is trying to calculate suggested retention.

To Reproduce
Steps to reproduce the behavior:

  1. Go to optimizer v.3.7.2
  2. Run it (I use Ctrl+F9)
  3. Wait until it gets to calculating suggested retention
  4. See error

Screenshots
1

Environment

  • OS: Windows 10
  • Optimizer version: v3.7.2

[Feature Request] Add fuzz to new intervals

Which module is related to your feature request?
Scheduler.

Is your feature request related to a problem? Please describe.
If I rate cards the same they will stick together forever and always come up for review on the same day. This can negatively affect learning.

This issue is addressed by Anki here:
https://docs.ankiweb.net/studying.html#fuzz-factor

Describe the solution you'd like
Add a small random delay to new intervals.

I wrote a simple function and use it myself, however, I don't know if it won't mess up the algorithm:

function fuzz(interval) {
  let delta;
  if (interval < 2.5) {
    delta = 0;
  } else if (interval < 10) {
    delta = 1;
  } else if (interval < 30) {
    delta = 2;
  } else if (interval < 50) {
    delta = 3;
  } else {
    delta = 4;
  }

  function random_in_range(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
  }

  const min_interval = Math.round(interval - delta);
  const max_interval = Math.round(interval + delta);

  return random_in_range(min_interval, max_interval);
}

Also, I edited this part of the code:

const hard_interval = constrain_interval(fuzz(last_s * hardInterval));
const good_interval = Math.max(constrain_interval(fuzz(customData.good.s)), hard_interval + 1);
const easy_interval = Math.max(constrain_interval(fuzz(customData.easy.s * easyBonus)), good_interval + 1);

It seems to work as intended.

Describe alternatives you've considered
I believe that here is the original solution of Anki:
https://github.com/ankitects/anki/blob/72b08cb7d51ddf6a3f51653b678fa0475b8cd0bb/rslib/src/scheduler/states/fuzz.rs

Maybe there is a way to use Anki's original solution?

[Feature Request] Making `w` easier to understand

Which module is related to your feature request?
Scheduler,

Is your feature request related to a problem? Please describe.
The meaning of w is not really clear. After all, it’s an array, but each specific position has a different meaning.

Describe the solution you'd like
Would you accept to use an object instead, so that keys allows me to understand the meaning of each parameter.
I’m willing to do the changes to the FAQ, the colab, and javascript. Also, to ensure that the javascript function still accept the current w format, so that any people who still have current values does not have to recompute it again.
I’d also accept to update https://github.com/open-spaced-repetition/fsrs4anki/wiki/Usage screenshot (in any case, I believe they need to be updated, since they don’t show the w, but some let variable = value.

[Question] Simulator - What is recall_repetitions, forget_repetitions, new_repetitions, and period_len

I'm testing the simulator and this is really cool, but I'm not 100% sure what recall_repetitions, forget_repetitions, new_repetitions, and period_len are

  1. Is recall_repetitions how many repetitions it takes to pass a "review" card? For example, in Anki, when I review an existing card, and I press good, that means it is 1 repetition. Not sure what happens when you press Again (fail card). I suppose this is counted for in forget_repetitions
  2. Is forget_repetitions how many repetitions it takes to review a card? For example, in Anki, in the options, there is "Lapses" section and I have the steps configured as "2 60", so would forget_repetitions be 2 here?
  3. Is new_repetitions how many repetitions it takes to learn a "new" card? For example, in Anki, in the options, there is the "New cards" section, and I have the steps configured as "1 5 60", so would new_repetitions be 3 here?
  4. Not sure what period_len is. In the graphs, I see "review cards per day (14 days average)" and "repetitions per day (14 days average)" since period_len=14 by default. Does this mean that you are adding a data point for every 14 days? So if I want to see the "review cards per day" and "repetitions per day" for every day, then I would set this to 1?

[Feature Request] Two Button Mode

Which module is related to your feature request?
Scheduler, Optimizer

Is your feature request related to a problem? Please describe.
I am only using Answer 1 (Again) or 3 (Good) since that is way more natural for me. Will this effect the efficency of fsrs4anki? Will the Optimizer give valid data for my past reviews?

Describe the solution you'd like
Implement a dedicated option in the scheduler and optimizer that accounts for the behavior of only using the buttons Again & Good.

Thank You!

[QUESTION] Is it possible to use this now with PC + IOS?

Is it possible to use this with the PC anki beta and the current version of IOS or will scheduling conflicts occur?
IOS does have the custom scheduling box.

Or is it possible to schedule from PC and then do the reviews etc?

I like the algorithm

Months need to pass before I can say anything more about it. But I already like it. The fact that cards that are stuck longer in the learning phase get to have a smaller graduating interval than cards that immediately leave is amazing. And I have wanted something like that for a long time

[Feature Request] Optimize parameters on data after a certain date/time

When exporting the anki collection and using fsrs4anki_optimizer to optimize the parameters on the revlog, the optimizer will use all time series data in the revlog. I think this is good since we need lots of data to get accurate results. However, I have used Anki wrong in the past where my retention rate would be really low, like 60-70%. Only recently I have fixed the issue and my retention rate in Anki is around 80-85%. However, since fsrs4anki_optimizer uses the whole revlog, it will include the data from when I reviewed cards poorly, meaning the parameters returned will be skewed, and hence there will be a bias to give short intervals

It would be nice if we can optionally specify a certain date for when the optimizer will start processing the data, such as

revlog_start_date = "2022-04-01"

Otherwise, if not specified (such as a default value of None), it will use the whole revlog data

[BUG] Running optimizer falied with no clue

Describe the bug
A clear and concise description of what the bug is.

As subject
To Reproduce
Steps to reproduce the behavior:

  1. Upload exported anki deck linux-kernel.apkg
  2. Change the file name and timezone
  3. Click on "Run all"
  4. Program stopped at 2.2 Train the model

Screenshots
2022-09-23_16-28

Environment

  • Anki version: Dev version 2.1.55
  • OS: Arch Linux
  • Optimizer version: v1.0.3 on Google Colab

The optimizer notebook seemed to fail on a SQL query

I uploaded my deck to Collab notebook, but the file extension was colpkg, not sure if this is OK. I then ran all the code, but looks like the execution stopped at a SQL query statement. I've attached a screenshot for this. Thank you.
2022-09-20_19-47

[Question] Decrease difficulty without pressing Easy? (Ease hell/Difficulty hell)

I've been playing around with the new update to fsrs4anki_optimizer version v1.6.1 and I love being able to see the rating_history, interval_history and difficulty_history.

One thing I noticed is that if you press Again (1), the difficulty will increase, and when you press Good (3), the difficulty stays the same. Only when you press Easy (4) the difficulty will decrease.

However, I use Anki slightly differently from most users. I only press Again (1) and Good (3). I never press Hard (2) or Easy (4). This means my grading style is binary (Pass or Fail). This is because it is much easier for me (less cognitively taxing) to grade my cards on a binary system; either I know the card or I don't know it, no in-between. But this also means that the difficulty for a card will always be the same. If I keep pressing Again (1), the difficulty will always increase, but never be able to decrease. This means that the intervals will be very short.

For example, with settings:

defaultDifficulty = 1.1873
defaultStability = 3.6988
difficultyDecay = -0.9949
stabilityDecay = -0.1412
retrievabilityFactor = 1.2742
increaseFactor = 2.9295
lapsesBase = -0.062

requestRetention = 0.9  # recommended setting: 0.8 ~ 0.9
easyBonus = 1.3
hardInterval = 1.2

test_rating_sequence = "3,1,3,1,3,1,3,3,3,3,3,3,3,3"

OUTPUT

rating history: 3,1,3,3,1,3,3,3,1,3,3,3,3,3
interval history: 0,4,4,8,15,3,6,10,17,3,5,8,12,18,27
difficulty history: 0,1.2,1.9,1.9,1.9,2.7,2.7,2.7,2.7,3.4,3.4,3.4,3.4,3.4,3.4

This is something known as "Ease hell" in the Anki community. Pressing Again (1) in Anki SM-2 will decrease the ease factor by 20%, pressing Hard (2) will decrease the ease factor by 15%, pressing Good will leave the ease factor the same, and pressing Easy will increase the ease factor by 15%. So we have the same behaviour in Anki SM-2. If we press Again (1) and Good (3) only, the ease factor will always decrease and never increase again since we don't press Easy (4). This means that the intervals will grow really slow if the ease factor stays around <=150%

I currently solve this issue by using an Anki Addon called Straight Reward which simply increases the ease factor if you press Good or Easy after X consecutive times (some Anki users use Auto Ease Factor addon instead to solve this issue). Here are my settings

image

This means that after pressing Good 3 times in a row, the ease factor will increase by 5%. And if I press Good 5 times in a row, it will increase by 5% + 5% * (5 - 3) = 15%, with an upper limit of 250% ease. This means that the card has a chance to regain its ease factor as long as I keep pressing Good consecutively.

I'm looking at the fsrs4anki_scheduler.js code and I see that there is some calculation here for the difficulty:

    const interval = states.current.normal?.review.elapsedDays ? states.current.normal.review.elapsedDays : states.current.filtered.rescheduling.originalState.review.elapsedDays;
    const last_d = customData.again.d;
    const last_s = customData.again.s;
    const retrievability = Math.exp(Math.log(0.9) * interval / last_s);
...
    customData.good.d = constrain_difficulty(last_d + retrievability - 1 + 0.1);
    customData.good.s = next_stability(customData.good.d, last_s, retrievability);

Correct me if I'm wrong, but it seems like pressing Good will decrease difficulty, but this doesn't seem to be the case in the fsrs4anki_optimizer. EDIT: Nevermind, it seems like interval = elapsedDays. I assume that's how many days has passed since the scheduled interval. For example, if the scheduledDays = 10 and 10 days has passed where I'm given the card by Anki, then elapsedDays=0. Otherwise, if 11 days has passed, and I finally review the card, then elapsedDays=1? If this is the case, then retrievability = e^(ln(0.9) * 0 / x) = 1 since I will always review cards every day and not miss a day. Then customData.good.d = constrain_difficulty(last_d + retrievability - 1 + 0.1) = constrain_difficulty(last_d + 1 - 1 + 0.1) = constrain_difficulty(last_d + 0.1) Seems like difficulty will always increase by 0.1 by pressing good. I feel like my math is wrong here... The optimizer doesn't change the difficulty at all when pressing good

If pressing Good (3) will never decrease the difficulty, even after consecutively pressing Good a few times, is it expected that we use the Easy button using fsrs4anki then? I don't expect the fsrs4anki algorithm to change to fit my use case, I'm open for new ideas, but I'm curious about the behaviour here and I'm interested in seeing how fsrs4anki handles this.

I also realize there is an issue with using Anki SM-2 + Straight Reward + Again/Good only solution. For mature cards, if ease factor is 250%, this means that the interval grows really fast (say, 365 days * 2.5 = 913 days). This is probably not the best interval for such a mature card. It'll be more likely that I forget this card and have to relearn it (This is probably the reason why I have 81.9% mature card retention rate, since the intervals are too large. My young card retention rate is ~88.2%). Using fsrs4anki algorithm, I get intervals:

first rating: 3
rating history: 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
interval history: 0,4,10,25,56,119,240,460,845,1493,2551,4227,6812,10707,16451,24757
difficulty history: 0,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2

where the change between each interval is

0 -> 4 = N/A
4 -> 10 = 10 / 4 = 2.5 = 250%
10 -> 25 = 25 / 10 = 2.5 = 250%
25 -> 56 = 56/ 25 = 2.24 = 224%
56 -> 119 = 119 / 56 = 2.125 = 212.5%
119 -> 240 = 240 / 119 = 2.017 = 201.7%
...

This shows that the change between each interval starts at 250% then decreases slowly as the card keeps maturing. This makes a lot of sense to me since the next optimal interval for a mature card probably doesn't increase as fast as 250% anymore compared to a young card.

Parameters for individual decks don't work

Describe the bug
You can specify parameters for each deck, but right now only global parameters affect scheduling.

To Reproduce
Steps to reproduce the behavior:

  1. Go to deck options and post code from fsrs4anki_scheduler.js in the window at the bottom of the settings
  2. Add this chunk:
if (document.getElementById('deck') !== null) {

    const deck_name = document.getElementById('deck').innerHTML;
    // parameters for a specific deck
    if (deck_name == "DeckName") {
        var f_s = [0.7712,0.837];
        var f_d = [1.0018,-0.9006,-1.1375,0.0935];
        var s_w = [3.0531,-0.8949,-0.1383,1.3434,2.1846,-0.2868,0.4257,1.245];

        requestRetention = 0.80;
        maximumInterval = 3650;
        easyBonus = 1.5;
        hardInterval = 1.2;
    }
}
  1. Try doing reviews with the above piece of code and without it (with global parameters)
  2. Compare the intervals, they should be different since the parameters are different

Expected behavior
Different sets of parameters should produce different intervals.

Environment

  • Anki version: 2.1.55
  • OS: Windows 10
  • Scheduler version: v2.0.3
  • Optimizer version: v2.0.3

Additional context
Here's all of my code:
code.txt

[Data] Sharing my Japanese revlog (~19k young+mature cards learned)

Data file
I'd like to share my revlog.csv from my Japanese collection which has about ~19,000 young+mature cards learned. There's about 515296 entries in this CSV file. I hope this will be useful for future developments of fsrs4anki! Feel free to use however you'd like :)

revlog.zip

Let me know if there's any other information you need

Additional context

  • Timezone: Canada/Eastern
  • The next day starts at: 8

[Feature Request] Need more instruction about how to tell if the algorithm is working

I was aware of this exact same question/answer in the Wike FAQ. I installed the AnkiWebView Inspector Anki add-on yesterday, however, I still didn't know what to look for as the interface appeared very messy to me probably because my web development knowledge was very limited, and therefore I was probably missing a lot of context. So I think it would be very helpful if @L-M-Sherlock could provide more details in documentation about how to confirm if the algorithm is working. I'm especially interested in this because I really couldn't tell the difference when I put this algorithm in use yesterday as it appeared to me that the scheduling was pretty much the same as if it was done by Anki's algorithm.

By the way, I noticed that @L-M-Sherlock had some new fixes or improvements regarding the filtered deck, because most of my reviews are performed in filtered deck, I'm not sure if I was affected.

The number of reviews durign optimization doesn't match the real number of reviews

Describe the bug
The number of reviews during optimization seems too low.

To Reproduce
Steps to reproduce the behavior:

  1. Check the number of reviews in the deck stats
  2. Check the number of reviews during the optimization
  3. Check if they are equal

Expected behavior
Both number should be equal.

Screenshots
https://i.imgur.com/3VeXp3H.png
https://i.imgur.com/UmD2kE3.png
revlog.csv

Environment

  • Anki version: ⁨2.1.55 (6944210f)⁩ Python 3.9.7 Qt 6.3.2 PyQt 6.3.1
  • OS: Windows 10
  • Scheduler version: v2.0.3
  • Optimizer version: v2.0.3

[Question] How to workaround with Anki custom scheduling not being "Per Deck"

I just figured out that Anki's Custom scheduling is shared between all the decks instead of being "per deck". I'm not sure whether this is good because my understanding is that the algorithm parameters should be different from deck to deck. In my case, the review performance of different decks are very different depending on how "hard" a deck is. Please correct me if my understanding is incorrect, but if my concern is legitimate, what's your suggestion to workaround it? Thank you.

[Feature Request] Adaption to exam learning

Which module is related to your feature request?
Scheduler & Optimizer

Besides long-term learning like languages, Anki often is used for exams. The difference would be that an exam is only 4 weeks, 3 months or something like that in the future. In case of university, normally the maximum is one semester = 6 months.

Is there a way to adapt your algorithm to this use case? If I understood it right, currently the use case is more long-term / language learning. This would be a real game changer, as often one is limited regarding available total learning time.

I'm thinking about something like a field in the optimizer where one can add the total available learning time additionally to the daily reviews.

Nevertheless thank you for this already incredible work!

[BUG] ValueError: shapes (6,) and (10,) not aligned: 6 (dim 0) != 10 (dim 0)

Describe the bug
Calculate the optimal retention leads to:

100%
13/13 [00:29<00:00, 2.69s/it]

expected_repetitions.csv saved.

---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

[<ipython-input-12-c87e08979336>](https://localhost:8080/#) in <module>
     64     optimal_retention_list.append(optimal_retention)
     65     plt.plot(retention, repetitions, label=f"d={d}, r={optimal_retention}")
---> 66 print(f"\n-----suggested retention: {np.inner(np.array(difficulty_distribution), np.array(optimal_retention_list)):.2f}-----")
     67 plt.ylabel("expected repetitions")
     68 plt.xlabel("retention")

<__array_function__ internals> in inner(*args, **kwargs)

ValueError: shapes (6,) and (10,) not aligned: 6 (dim 0) != 10 (dim 0)

Environment
FSRS4Anki v3.7.2 Optimizer

[BUG] Invalid argument when extracting .apkg file

Describe the bug
Error appears when extracting the apkg file. Doesn't happen when the support older anki versions export button is checked.

OSError                                   Traceback (most recent call last)

[<ipython-input-12-f1fb03115c22>](https://localhost:8080/#) in <module>
      2 # Extract the collection file or deck file to get the .anki21 database.
      3 with zipfile.ZipFile(f'./{filename}', 'r') as zip_ref:
----> 4     zip_ref.extractall('./')
      5     print("Extract successfully!")

3 frames

[/usr/lib/python3.7/zipfile.py](https://localhost:8080/#) in read(self, n)
    751                         "is an open writing handle on it. "
    752                         "Close the writing handle before trying to read.")
--> 753             self._file.seek(self._pos)
    754             data = self._file.read(n)
    755             self._pos = self._file.tell()

OSError: [Errno 22] Invalid argument

To Reproduce
Steps to reproduce the behavior:

  1. Upload apkg file
  2. Click on Runtime -> Run all
  3. Extraction fails

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Environment

  • Anki version: [2.1.55]
  • OS: [Arch Linux]
  • Scheduler version: [v3]
  • Optimizer version: [v1.0.3]
  • Simulator version: [v1.1.0]

[BUG] Seeing different intervals for the same card on different computers.

Describe the bug
Hi! I'm seeing different intervals for the same card on anki on different computers. Both are synced correctly, using the same settings.

Expected behavior
I believe they should present the same intervals, right?

Screenshots
On my pc
Captura de tela de 2022-10-10 01-20-02

On my notebook
Captura de tela de 2022-10-10 01-19-09

Environment

  • Anki version: 2.1.55
  • OS: Fedora and Manjaro
  • Scheduler version: 3.20
  • Optimizer version: 3.20

[BUG] incompatibility with add-on Straight Reward

Describe the bug
Straight Reward addon seems to crash instead of changing ease

To Reproduce
Steps to reproduce the behavior:

  1. install add-on
  2. configure it to give certain ease after answering the same card X times.
    3). See error

Expected behavior
Add-on should not crash

debug

Caught exception:
Traceback (most recent call last):
File "aqt.webview", line 553, in handler
File "aqt.reviewer", line 532, in _onAnswerButton
File "decorator", line 232, in fun
File "anki.hooks", line 89, in decorator_wrapper
File "anki.hooks", line 84, in repl
File "aqt.reviewer", line 431, in _answerCard
File "aqt.hooks_gen", line 3807, in __call__
File "[…]\AppData\Roaming\Anki2\addons21\957961234\src\lib\review_hook.py", line 101, in <lambda>
lambda ease_tuple, reviewer, card: on_will_answer_card(
File "[…]AppData\Roaming\Anki2\addons21\957961234\src\lib\review_hook.py", line 85, in on_will_answer_card
check_straight_reward(gains, reviewer, card, ease_tuple[1])
File "[…] \AppData\Roaming\Anki2\addons21\957961234\src\lib\review_hook.py", line 64, in check_straight_reward
next_states = reviewer.get_next_states()
AttributeError: 'Reviewer' object has no attribute 'get_next_states'

Environment

  • Anki version: [e.g. 2.1.55]
  • OS: [Windows 11]
  • Scheduler version: [v2.0.3]
  • Optimizer version: [v2.0.3]

Changing easyBonus and hardInterval doesn't affect intervals

Describe the bug
Changing easyBonus and hardInterval in fsrs4anki_scheduler.js v2.0.3 doesn't affect intervals. To be fair, I don't understand why they even should affect intervals in the first place, I thought the new algorithm handles it on its own, based on it's own calculations of D and other stuff.

To Reproduce
Steps to reproduce the behavior:

  1. Copy and paste code from fsrs4anki_scheduler.js v2.0.3 into the window in deck options
  2. Try changing the values of easyBonus and/or hardInterval
  3. See if it affects intervals

Expected behavior
Different values should correspond to different intervals.

Screenshots
https://i.imgur.com/rqaLLAo.png

Environment

  • Anki version: ⁨2.1.55 (6944210f)⁩ Python 3.9.7 Qt 6.3.2 PyQt 6.3.1
  • OS: Windows 10
  • Scheduler version: 2.0.3

A mistake or something

Hi. I wanted to try your schedule but I have this mistake. Anki 2.1.55 beta 6, Mac OS Bug Sur 11.7.1. It's a new collection and it doesn't have any add-ons except AnkiWEb Inspector.

Screen Shot 2022-11-28 at 9 08 01 PM

Screen Shot 2022-11-28 at 9 08 21 PM

执行FSRS4Anki v3.5.0 Optimizer的1.2步骤时出现"KeyError"[BUG]

Describe the bug
使用Anki v2.1.55 beta 2导出的.apkg文件(已经勾选了兼容旧版本),
执行FSRS4Anki v3.5.0 Optimizer的1.2步骤时出现"KeyError"
如有需要,可以邮件发您使用的.apkg文件

KeyError Traceback (most recent call last)
in
66 return group
67
---> 68 df = df.groupby(by=['r_history', 'delta_t']).progress_apply(cal_retention)
69 print("Retention calculated.")
70 df = df.drop(columns=['id', 'cid', 'usn', 'ivl', 'last_lvl', 'factor', 'time', 'type', 'create_date', 'review_date', 'real_days', 'r', 't_history'])

9 frames
/usr/local/lib/python3.7/dist-packages/tqdm/std.py in inner(df, func, *args, **kwargs)
812 # on the df using our wrapper (which provides bar updating)
813 try:
--> 814 return getattr(df, df_function)(wrapper, **kwargs)
815 finally:
816 t.close()

/usr/local/lib/python3.7/dist-packages/pandas/core/groupby/groupby.py in apply(self, func, *args, **kwargs)
1273 with option_context("mode.chained_assignment", None):
1274 try:
-> 1275 result = self._python_apply_general(f, self._selected_obj)
1276 except TypeError:
1277 # gh-20949

/usr/local/lib/python3.7/dist-packages/pandas/core/groupby/groupby.py in _python_apply_general(self, f, data)
1307 data after applying f
1308 """
-> 1309 keys, values, mutated = self.grouper.apply(f, data, self.axis)
1310
1311 return self._wrap_applied_output(

/usr/local/lib/python3.7/dist-packages/pandas/core/groupby/ops.py in apply(self, f, data, axis)
850 # group might be modified
851 group_axes = group.axes
--> 852 res = f(group)
853 if not _is_indexed_like(res, group_axes, axis):
854 mutated = True

/usr/local/lib/python3.7/dist-packages/tqdm/std.py in wrapper(*args, **kwargs)
807 # take a fast or slow code path; so stop when t.total==t.n
808 t.update(n=1 if not t.total or t.n < t.total else 0)
--> 809 return func(*args, **kwargs)
810
811 # Apply the provided function (in **kwargs)

in cal_retention(group)
62
63 def cal_retention(group: pd.DataFrame) -> pd.DataFrame:
---> 64 group['retention'] = round(group['r'].map(lambda x: {1: 0, 2: 1, 3: 1, 4: 1}[x]).mean(), 4)
65 group['total_cnt'] = group.shape[0]
66 return group

/usr/local/lib/python3.7/dist-packages/pandas/core/series.py in map(self, arg, na_action)
4159 dtype: object
4160 """
-> 4161 new_values = super()._map_values(arg, na_action=na_action)
4162 return self._constructor(new_values, index=self.index).finalize(
4163 self, method="map"

/usr/local/lib/python3.7/dist-packages/pandas/core/base.py in _map_values(self, mapper, na_action)
868
869 # mapper is a function
--> 870 new_values = map_f(values, mapper)
871
872 return new_values

/usr/local/lib/python3.7/dist-packages/pandas/_libs/lib.pyx in pandas._libs.lib.map_infer()

in (x)
62
63 def cal_retention(group: pd.DataFrame) -> pd.DataFrame:
---> 64 group['retention'] = round(group['r'].map(lambda x: {1: 0, 2: 1, 3: 1, 4: 1}[x]).mean(), 4)
65 group['total_cnt'] = group.shape[0]
66 return group

KeyError: 0

Environment

  • Anki version: [2.1.55 beta 2]
  • OS: [macOS 13 beta (22A5373b)]

Recalculate intervals for all cards in the deck when requestRetention or maximumInterval are changed

Which module is related to your feature request?
Scheduler

Is your feature request related to a problem? Please describe.
Currently, even if the user changes requestRetention or maximumInterval, it will only affect future reviews, but won't affect past reviews and hence the current intervals of cards in the deck. Suppose user always had requestRetention = 0.9 and now he wants to set it to 0.8, but all the cards he has reviewed so far are scheduled using requestRetention = 0.9. Or maybe the user just started using FSRS and his cards aren't even scheduled according to FSRS. Or maybe the user changed parameters and wants to re-calculate the intervals using new parameters. Same goes for changing maximumInterval.

Describe the solution you'd like
There should be a button (if possible) such that after pressing it the algorithm will re-calculate intervals for all cards in the current deck that have at least 1 review.

Error in the Anki Inspector when using scheduler v3.0.0

Describe the bug
Anki Inspector shows that there is an error in the code. See screenshots for more info.

To Reproduce
Steps to reproduce the behavior:

  1. Paste code from fsrs4anki_scheduler.js to the window in deck options
  2. Review a card while using Anki Inspector
  3. See error in the code shown by Anki Inspector

Expected behavior
There should be no error.

Screenshots
1
2

Environment

  • Anki version: 2.1.55
  • OS: Windows 10
  • Scheduler version: v3.0.0

Additional context
First I tried a modified version of code, with many else if statements. Then I tried the unmodified version.

Some question about this project

Hello
I wanted to ask some questions about this project of yours.
1- What does this Custom scheduling which is FSRS does? its difference with anki default scheduler? With example please! and in ELI5 mode (Explain like i'm 5 years old)
2- Who are the target community of this project?
Sorry for these noob like questions

Incorrect graduating interval for new cards

Describe the bug
The interval that corresponds to "Easy" (aka graduating for new cards) during the first review doesn't match the learning step I set in the deck options. See screenshots.

To Reproduce
Steps to reproduce the behavior:

  1. Go to deck options and set learning steps and the graduating interval
  2. Review a new card for the first time
  3. Check if the "Easy" interval (aka graduating interval) with this FSRS corresponds to the "Easy" (graduating) interval without FSRS

Expected behavior
Since FSRS isn't supposed to affect learning steps and graduating intervals, both intervals should be the same, with or without FSRS

Screenshots
1

Environment

  • Anki version: 2.1.55
  • OS: Windows 10
  • Scheduler version: v.2.1.0

Add a check to ensure that hard intervals cannot be longer than good intervals.

Which module is related to your feature request?
Scheduler

Is your feature request related to a problem? Please describe.
Sometimes I see cards with hard intervals longer than good intervals. However, it doesn't seem like a problem with FSRS itself, but rather a problem of how it interacts with user-specified learning steps. If one of the learning steps is greater than 1 day this sometimes happens (I don't have a screenshot right now, unfortunately), so for now I have to set all my learning steps across almost all decks to 1 day to avoid this.

Describe the solution you'd like
Add something like this to the scheduler:

if NewInterval.hard > NewInterval.good:
    NewInterval.hard = NewInterval.good
else:
    NewInterval.hard

[Bug] fix for the bug I had

notroundnumber = stability * np.log(requestRetention) / np.log(0.9)
        if math.isnan(roundnumber):
          roundnumber = 0
        return min(max(1, round(notroundnumber)), maximumInterval)

[BUG] Scheduled interval is not the same as what "Good" button says

Describe the bug
As subject

To Reproduce
Steps to reproduce the behavior:

  1. Click the filtered deck which was filtered with deck:Python is:due is:learn
  2. Click the Study Now
  3. After reviewing, click Good, and the button suggested the next review would be in 4 days.
  4. Open the card browser, find the card just got reviewed to check the interval, but it says 1 day

Expected behavior
The interval should be the same as the Good button says, i.e., 4 days in this case.

Screenshots
2022-09-23_20-01

Environment

  • Anki version: Dev version 2.1.55
  • OS: Arch Linux
  • Scheduler version: 1.4.2
  • Optimizer version: 1.4.0

[question] FSRS4Anki suggested retention quite low?

I started using FSRS4Anki some time ago, seems to produce better results than standard Anki algorithm, especially in the early learning stages.
I am using Anki mainly for languages learning, so keeping good retention of material over a long period of time is significant factor for me.
For now I used FSRS4Anki with retention set to 0.9. However the optimizer is suggesting me that "the optimal retention to minimize the repetitions for long-term memory consolidation" for my deck is 0.83.
I am little hesitant to lower the target retention as I have a gut feeling, that in such case I will have more cards that I already forgot but are not yet due.
Any opinions on this?

Answer to a FAQ question

Hi,

AnkiDroid maintainer here. Sorry to use Issues to contact you, but I’m not sure what the best way to do it.
In the FAQ, you mention

I don't know how AnkiDroid deals with the customData in the card field

So, I can tell you. customData is a field specific to scheduler v3. We don’t support it. And sadly, we don’t even have an idea of when we’ll actually support it, because Android Play store does not allow us to update the app until we make some complex changes.

However, I can ensure to let you know when it’s done, so you can update the faq

[BUG] Got "0 seconds" interval after reviewing with "Good" rate

Describe the bug
Got scheduled at "0 seconds" interval after reviewing with "Good" rate

To Reproduce
Steps to reproduce the behavior:

  1. Click the filtered deck with the filter
   deck:XXXX is:due is:learn
  1. Click on Study Now
  2. Click on Show Anwer
  3. Click on Good button

Expected behavior
Scheduled with a non-zero interval

Screenshots
See the attached screenshot

Environment

  • Anki version: dev version 2.1.55
  • OS: Arch Linux
  • Scheduler version: V3
  • Optimizer version: git commit eccd894
  • Simulator version: N/A

2022-09-22_23-26

[BUG] An error when using scheduler v.3.4.0

Describe the bug
I noticed that my intervals were off, so I checked whetehr the code was running properly using AnkiWeb Inspector, and found the error in the screenshot.

To Reproduce
Steps to reproduce the behavior:

  1. Copy code from https://github.com/open-spaced-repetition/fsrs4anki/blob/main/fsrs4anki_scheduler.js
  2. Paste it in the window for custom code, in deck options
  3. Use AnkiWeb Inspector to check for errors
  4. See error at line 40

Screenshots
1

Environment

  • Anki version: ⁨2.1.55 (6944210f)⁩, Python 3.9.7 Qt 6.3.2 PyQt 6.3.1
  • OS: Windows 10
  • Scheduler version: v3.4.0

Additional context
Originally I thought I messed up the code while adding more else if statements, but it seems like this problem still remains even with the code directly copied from fsrs4anki_scheduler.js without any modifications. I also made sure that all cards have <div id=deck deck_name="{{Deck}}"></div> on the front side, so that's not what's causing the problem.

[Question] Intervals for new cards

Hi. My Anki settings for new cards are default. When I use default scheduler, my intervals for new cards are mostly 1 day. When I use your scheduler, my intervals are mostly 4 day, sometimes 3 and hardly ever 2. I prefer mostly 1 day because they're new cards. Is it any way to change it?

[Feature Request?] Adding a variable to the custom scheduler without interfering with FSRS scheduling

Which module is related to your feature request?
Scheduler

Is your feature request related to a problem? Please describe.
I'm trying to add the following variable so I can change the display of the template depending on the interval of the card.

globalThis.intervalTest = states.current.normal.review.elapsedDays;

But then the easy button interval for example, goes from 7 days to 2 days.

Describe the solution you'd like
A way to use the card's current interval value in the template without affecting FSRS scheduling.

Describe alternatives you've considered
Using additional card fields addon
or every X days, selecting cards with interval > Ydays and bulk filling a field that I will use with conditional replacement

Additional context
The point is to review sentence cards until they have a certain interval, let's say the mature interval(21days), then they become vocab cards, this way I can internalize the context and the reviewing time is back to normal(faster) after 21 days.
If you think this is stupid or just less efficient, please tell me, I'll forget about this idea.

[BUG]

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to simulator
  2. Upload exported deck
  3. start the simulator
  4. See error

ValueError Traceback (most recent call last)
in
128 card.iat[idx, field_map['repetitions']] += recall_repetitions
129
--> 130 delta_t, factor = scheduler(scheduler_name, (stability, new_stability, rating),(due-last_date, ivl, factor, rating))
131 card.iat[idx, field_map['factor']] = factor
132 card.iat[idx, field_map['due']] = day + delta_t

2 frames
in constrain_interval(stability)
21 def fsrs4anki_scheduler(last_stability, stability, rating):
22 def constrain_interval(stability):
---> 23 return min(max(1, round(stability * np.log(requestRetention) / np.log(0.9))), maximumInterval)
24 if last_stability is None:
25 return constrain_interval(stability)

ValueError: cannot convert float NaN to integer

Screenshots
If applicable, add screenshots to help explain your problem.

Environment

  • Anki version: [e.g. 2.1.55]
  • OS: linux
  • Simulator version: 1.8.0

Additional context
Add any other context about the problem here.

In optimizer v.2.2.0 "import zipfile" doesn't work properly

Describe the bug
import zipfile produces an error. For some reason it only affects certain decks, not every deck

To Reproduce
Steps to reproduce the behavior:

  1. Enter the name of your deck in filename, then enter your timezone and next_day_starts_at
  2. Run that code
  3. Run the next piece of code, the one that starts with import zipfile
  4. See error

Expected behavior
There should be no error.

Screenshots
1

Environment

  • OS: Windows 10
  • Optimizer version: v2.2.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.