Skip to content

Commit 90d5695

Browse files
authored
Fix/apply max interval to SM-2 (#527)
1 parent 25cf920 commit 90d5695

2 files changed

Lines changed: 48 additions & 29 deletions

File tree

fsrs4anki_optimizer.ipynb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
"cell_type": "markdown",
66
"metadata": {},
77
"source": [
8-
"# FSRS4Anki v4.10.1 Optimizer\n",
8+
"# FSRS4Anki v4.10.2 Optimizer\n",
99
"\n",
10-
"[![open in colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/open-spaced-repetition/fsrs4anki/blob/v4.10.1/fsrs4anki_optimizer.ipynb)\n",
10+
"[![open in colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/open-spaced-repetition/fsrs4anki/blob/v4.10.2/fsrs4anki_optimizer.ipynb)\n",
1111
"\n",
1212
"↑ Click the above button to open the optimizer on Google Colab.\n",
1313
"\n",
@@ -112,7 +112,7 @@
112112
}
113113
],
114114
"source": [
115-
"%pip install -q fsrs_optimizer==4.18.1\n",
115+
"%pip install -q fsrs_optimizer==4.18.2\n",
116116
"# for local development\n",
117117
"# import os\n",
118118
"# import sys\n",

fsrs4anki_simulator.ipynb

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"id": "jmXx-hS9ZMVj"
88
},
99
"source": [
10-
"# FSRS4Anki v4.10.0 Simulator"
10+
"# FSRS4Anki v4.10.2 Simulator"
1111
]
1212
},
1313
{
@@ -17,7 +17,7 @@
1717
"id": "lurCmW0Jqz3s"
1818
},
1919
"source": [
20-
"[![open in colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/open-spaced-repetition/fsrs4anki/blob/v4.8.3/fsrs4anki_simulator.ipynb)\n",
20+
"[![open in colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/open-spaced-repetition/fsrs4anki/blob/v4.10.2/fsrs4anki_simulator.ipynb)\n",
2121
"\n",
2222
"↑ Click the above button to open the simulator on Google Colab.\n",
2323
"\n",
@@ -90,10 +90,11 @@
9090
}
9191
],
9292
"source": [
93-
"# %pip install -q fsrs_optimizer==4.18.0\n",
93+
"%pip install -q fsrs_optimizer==4.18.2\n",
9494
"import pandas as pd\n",
9595
"import numpy as np\n",
9696
"import random\n",
97+
"\n",
9798
"# for local development\n",
9899
"# import os\n",
99100
"# import sys\n",
@@ -111,20 +112,25 @@
111112
"df = pd.read_csv(\"./revlog.csv\")\n",
112113
"df.sort_values(by=[\"card_id\", \"review_time\"], inplace=True, ignore_index=True)\n",
113114
"\n",
114-
"new_card_revlog = df[(df[\"review_state\"] == New) & (df[\"review_rating\"].isin([1, 2, 3, 4]))]\n",
115+
"new_card_revlog = df[\n",
116+
" (df[\"review_state\"] == New) & (df[\"review_rating\"].isin([1, 2, 3, 4]))\n",
117+
"]\n",
115118
"first_rating_prob = np.zeros(4)\n",
116119
"first_rating_prob[new_card_revlog[\"review_rating\"].value_counts().index - 1] = (\n",
117120
" new_card_revlog[\"review_rating\"].value_counts()\n",
118121
" / new_card_revlog[\"review_rating\"].count()\n",
119122
")\n",
120-
"recall_card_revlog = df[(df[\"review_state\"] == Review) & (df[\"review_rating\"].isin([2, 3, 4]))]\n",
123+
"recall_card_revlog = df[\n",
124+
" (df[\"review_state\"] == Review) & (df[\"review_rating\"].isin([2, 3, 4]))\n",
125+
"]\n",
121126
"review_rating_prob = np.zeros(3)\n",
122127
"review_rating_prob[recall_card_revlog[\"review_rating\"].value_counts().index - 2] = (\n",
123128
" recall_card_revlog[\"review_rating\"].value_counts()\n",
124129
" / recall_card_revlog[\"review_rating\"].count()\n",
125130
")\n",
126131
"\n",
127-
"df[\"review_state\"] = df[\"review_state\"].map(lambda x: x if x != New else Learning)\n",
132+
"df[\"review_state\"] = df[\"review_state\"].map(\n",
133+
" lambda x: x if x != New else Learning)\n",
128134
"\n",
129135
"recall_costs = np.zeros(3)\n",
130136
"recall_costs_df = recall_card_revlog.groupby(by=\"review_rating\")[\n",
@@ -150,7 +156,8 @@
150156
"state_duration[last_state] = duration_sequence[0]\n",
151157
"for i, state in enumerate(state_sequence[1:]):\n",
152158
" state_count[state] = state_count.setdefault(state, 0) + 1\n",
153-
" state_duration[state] = state_duration.setdefault(state, 0) + duration_sequence[i]\n",
159+
" state_duration[state] = state_duration.setdefault(\n",
160+
" state, 0) + duration_sequence[i]\n",
154161
" if state != last_state:\n",
155162
" state_block[state] = state_block.setdefault(state, 0) + 1\n",
156163
" last_state = state\n",
@@ -159,7 +166,8 @@
159166
"\n",
160167
"if Relearning in state_count and Relearning in state_block:\n",
161168
" forget_cost = round(\n",
162-
" state_duration[Relearning] / state_block[Relearning] / 1000 + recall_cost,\n",
169+
" state_duration[Relearning] /\n",
170+
" state_block[Relearning] / 1000 + recall_cost,\n",
163171
" 1,\n",
164172
" )\n",
165173
"\n",
@@ -364,23 +372,33 @@
364372
" if factor is None:\n",
365373
" return (graduatingInterval, 2.5) if rating != 4 else (easyInterval, 2.5)\n",
366374
" delay = real_interval - interval\n",
367-
" again_interval = max(\n",
368-
" round(interval * newInterval * intervalModifier + 0.01), minimumInterval\n",
375+
" again_interval = min(\n",
376+
" max(round(interval * newInterval * intervalModifier + 0.01), minimumInterval),\n",
377+
" maximumInterval,\n",
369378
" )\n",
370-
" hard_interval = max(\n",
371-
" round(interval * hardInterval * intervalModifier + 0.01),\n",
372-
" interval + 1,\n",
373-
" minimumInterval,\n",
379+
" hard_interval = min(\n",
380+
" max(\n",
381+
" round(interval * hardInterval * intervalModifier + 0.01),\n",
382+
" interval + 1,\n",
383+
" minimumInterval,\n",
384+
" ),\n",
385+
" maximumInterval,\n",
374386
" )\n",
375-
" good_interval = max(\n",
376-
" round((interval + delay / 2) * factor * intervalModifier + 0.01),\n",
377-
" hard_interval + 1,\n",
378-
" minimumInterval,\n",
387+
" good_interval = min(\n",
388+
" max(\n",
389+
" round((interval + delay / 2) * factor * intervalModifier + 0.01),\n",
390+
" hard_interval + 1,\n",
391+
" minimumInterval,\n",
392+
" ),\n",
393+
" maximumInterval,\n",
379394
" )\n",
380-
" easy_interval = max(\n",
381-
" round(real_interval * factor * intervalModifier * easyBonus + 0.01),\n",
382-
" good_interval + 1,\n",
383-
" minimumInterval,\n",
395+
" easy_interval = min(\n",
396+
" max(\n",
397+
" round(real_interval * factor * intervalModifier * easyBonus + 0.01),\n",
398+
" good_interval + 1,\n",
399+
" minimumInterval,\n",
400+
" ),\n",
401+
" maximumInterval,\n",
384402
" )\n",
385403
" if rating == 1:\n",
386404
" return again_interval, max(factor - 0.2, 1.3)\n",
@@ -556,15 +574,15 @@
556574
"\n",
557575
" if day >= moving_average_period:\n",
558576
" new_card_per_day_average_per_period[day] = np.true_divide(\n",
559-
" new_card_per_day[day - moving_average_period : day].sum(),\n",
577+
" new_card_per_day[day - moving_average_period: day].sum(),\n",
560578
" moving_average_period,\n",
561579
" )\n",
562580
" review_card_per_day_average_per_period[day] = np.true_divide(\n",
563-
" review_card_per_day[day - moving_average_period : day].sum(),\n",
581+
" review_card_per_day[day - moving_average_period: day].sum(),\n",
564582
" moving_average_period,\n",
565583
" )\n",
566584
" time_per_day_average_per_period[day] = np.true_divide(\n",
567-
" time_per_day[day - moving_average_period : day].sum(),\n",
585+
" time_per_day[day - moving_average_period: day].sum(),\n",
568586
" moving_average_period,\n",
569587
" )\n",
570588
" else:\n",
@@ -598,7 +616,8 @@
598616
" print(\"learned cards:\", total_learned)\n",
599617
" print(\"time in minutes:\", round(total_time / 60, 1))\n",
600618
" print(\"remembered cards:\", total_remembered)\n",
601-
" print(\"time per remembered card:\", round(total_time / 60 / total_remembered, 2))\n",
619+
" print(\"time per remembered card:\", round(\n",
620+
" total_time / 60 / total_remembered, 2))\n",
602621
" print(\"leeches:\", total_leeches)\n",
603622
"\n",
604623
" save = card[card[\"retrievability\"] > 0].copy()\n",

0 commit comments

Comments
 (0)