File size: 129,356 Bytes
651b002
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# FSRS4Anki v3.10.1 Optimizer"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "id": "lurCmW0Jqz3s"
   },
   "source": [
    "[![open in colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/open-spaced-repetition/fsrs4anki/blob/v3.10.1/fsrs4anki_optimizer.ipynb)\n",
    "\n",
    "↑ Click the above button to open the optimizer on Google Colab.\n",
    "\n",
    "> If you can't see the button and are located in the Chinese Mainland, please use a proxy or VPN."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "wG7bBfGJFbMr"
   },
   "source": [
    "Upload your **Anki Deck Package (.apkg)** file or **Anki Collection Package (.colpkg)** file on the `Left sidebar -> Files`, drag and drop your file in the current directory (not the `sample_data` directory). \n",
    "\n",
    "No need to include media. Need to include scheduling information. \n",
    "\n",
    "> If you use the latest version of Anki, please check the box `Support older Anki versions (slower/larger files)` when you export.\n",
    "\n",
    "You can export it via `File -> Export...` or `Ctrl + E` in the main window of Anki.\n",
    "\n",
    "Then replace the `filename` with yours in the next code cell. And set the `timezone` and `next_day_starts_at` which can be found in your preferences of Anki.\n",
    "\n",
    "After that, just run all (`Runtime -> Run all` or `Ctrl + F9`) and wait for minutes. You can see the optimal parameters in section **3 Result**. Copy them, replace the parameters in `fsrs4anki_scheduler.js`, and paste them into the custom scheduling of your deck options (require Anki version >= 2.1.55).\n",
    "\n",
    "**NOTE**: The default output is generated from my review logs. If you find the output is the same as mine, maybe your notebook hasn't run there.\n",
    "\n",
    "**Contribute to SRS Research**: If you want to share your data with me, please fill this form: https://forms.gle/KaojsBbhMCytaA7h8"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "id": "iqP70_-3EUhi"
   },
   "outputs": [],
   "source": [
    "# Here are some settings that you need to replace before running this optimizer.\n",
    "\n",
    "filename = \"collection-2022-09-18@13-21-58.colpkg\"\n",
    "# If you upload deck file, replace it with your deck filename. E.g., ALL__Learning.apkg\n",
    "# If you upload collection file, replace it with your colpgk filename. E.g., collection-2022-09-18@13-21-58.colpkg\n",
    "\n",
    "# Replace it with your timezone. I'm in China, so I use Asia/Shanghai.\n",
    "# You can find your timezone here: https://gist.github.com/heyalexej/8bf688fd67d7199be4a1682b3eec7568\n",
    "timezone = 'Asia/Shanghai'\n",
    "\n",
    "# Replace it with your Anki's setting in Preferences -> Scheduling.\n",
    "next_day_starts_at = 4\n",
    "\n",
    "# Replace it if you don't want the optimizer to use the review logs before a specific date.\n",
    "revlog_start_date = \"2006-10-05\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "bLFVNmG2qd06"
   },
   "source": [
    "## 1 Build dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "EkzFeKawqgbs"
   },
   "source": [
    "### 1.1 Extract Anki collection & deck file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "KD2js_wEr_Bs",
    "outputId": "42653d9e-316e-40bc-bd1d-f3a0e2b246c7"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extract successfully!\n"
     ]
    }
   ],
   "source": [
    "import zipfile\n",
    "import sqlite3\n",
    "import time\n",
    "import tqdm\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import os\n",
    "from datetime import timedelta, datetime\n",
    "import matplotlib.pyplot as plt\n",
    "import math\n",
    "import sys\n",
    "import torch\n",
    "from torch import nn\n",
    "from sklearn.utils import shuffle\n",
    "# Extract the collection file or deck file to get the .anki21 database.\n",
    "with zipfile.ZipFile(f'./{filename}', 'r') as zip_ref:\n",
    "    zip_ref.extractall('./')\n",
    "    print(\"Extract successfully!\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "dKpy4VfqGmaL"
   },
   "source": [
    "### 1.2 Create time-series feature & analysis\n",
    "\n",
    "The following code cell will extract the review logs from your Anki collection and preprocess them to a trainset which is saved in `revlog_history.tsv`.\n",
    "\n",
    "The time-series features are important in optimizing the model's parameters. For more detail, please see my paper: https://www.maimemo.com/paper/\n",
    "\n",
    "Then it will generate a concise analysis for your review logs. \n",
    "\n",
    "- The `r_history` is the history of ratings on each review. `3,3,3,1` means that you press `Good, Good, Good, Again`. It only contains the first rating for each card on the review date, i.e., when you press `Again` in review and  `Good` in relearning steps 10min later, only `Again` will be recorded.\n",
    "- The `avg_interval` is the actual average interval after you rate your cards as the `r_history`. It could be longer than the interval given by Anki's built-in scheduler because you reviewed some overdue cards.\n",
    "- The `avg_retention` is the average retention after you press as the `r_history`. `Again` counts as failed recall, and `Hard, Good and Easy` count as successful recall. Retention is the percentage of your successful recall.\n",
    "- The `stability` is the estimated memory state variable, which is an approximate interval that leads to 90% retention.\n",
    "- The `factor` is `stability / previous stability`.\n",
    "- The `group_cnt` is the number of review logs that have the same `r_history`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "J2IIaY3PDaaG",
    "outputId": "607916c9-da95-48dd-fdab-6bd83fbbbb40"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "revlog.csv saved.\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "fec0c445154d4182bbff35e17f98e0ef",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/30711 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Trainset saved.\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "8c0036ef716b420983b5569158548ae4",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/96660 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Retention calculated.\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "0464e344b70741d3a93c91802369b448",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1312 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Stability calculated.\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1bfca6ff3bda45a59f7d9bd871434a59",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1312 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1:again, 2:hard, 3:good, 4:easy\n",
      "\n",
      "  r_history  avg_interval  avg_retention  stability  factor  group_cnt\n",
      "          1           1.7          0.765        1.0     inf       7978\n",
      "        1,3           3.9          0.876        4.3    4.30       4155\n",
      "      1,3,3           8.6          0.883        9.2    2.14       2684\n",
      "    1,3,3,3          17.8          0.857       13.8    1.50       1483\n",
      "  1,3,3,3,3          37.0          0.812       19.4    1.41        606\n",
      "1,3,3,3,3,3          77.1          0.708       23.1    1.19        128\n",
      "          2           1.0          0.901        1.1     inf        234\n",
      "        2,3           3.2          0.943        6.3    5.73        154\n",
      "          3           1.5          0.962        5.4     inf       9070\n",
      "        3,3           3.9          0.966       15.2    2.81       6527\n",
      "      3,3,3           9.0          0.960       23.5    1.55       5036\n",
      "    3,3,3,3          18.6          0.941       35.2    1.50       3052\n",
      "  3,3,3,3,3          39.5          0.914       46.9    1.33       1423\n",
      "3,3,3,3,3,3          74.3          0.853       55.6    1.19        411\n",
      "          4           3.8          0.966       12.1     inf      11436\n",
      "        4,3           8.1          0.975       38.9    3.21       7367\n",
      "      4,3,3          18.0          0.963       57.7    1.48       5147\n",
      "    4,3,3,3          34.0          0.947       77.2    1.34       2525\n",
      "  4,3,3,3,3          46.3          0.906       50.1    0.65        452\n",
      "Analysis saved!\n"
     ]
    }
   ],
   "source": [
    "if os.path.isfile(\"collection.anki21b\"):\n",
    "    os.remove(\"collection.anki21b\")\n",
    "    raise Exception(\n",
    "        \"Please export the file with `support older Anki versions` if you use the latest version of Anki.\")\n",
    "elif os.path.isfile(\"collection.anki21\"):\n",
    "    con = sqlite3.connect(\"collection.anki21\")\n",
    "elif os.path.isfile(\"collection.anki2\"):\n",
    "    con = sqlite3.connect(\"collection.anki2\")\n",
    "else:\n",
    "    raise Exception(\"Collection not exist!\")\n",
    "cur = con.cursor()\n",
    "res = cur.execute(\"SELECT * FROM revlog\")\n",
    "revlog = res.fetchall()\n",
    "\n",
    "df = pd.DataFrame(revlog)\n",
    "df.columns = ['id', 'cid', 'usn', 'r', 'ivl',\n",
    "              'last_lvl', 'factor', 'time', 'type']\n",
    "df = df[(df['cid'] <= time.time() * 1000) &\n",
    "        (df['id'] <= time.time() * 1000) &\n",
    "        (df['r'] > 0) &\n",
    "        (df['id'] >= time.mktime(datetime.strptime(revlog_start_date, \"%Y-%m-%d\").timetuple()) * 1000)].copy()\n",
    "df['create_date'] = pd.to_datetime(df['cid'] // 1000, unit='s')\n",
    "df['create_date'] = df['create_date'].dt.tz_localize(\n",
    "    'UTC').dt.tz_convert(timezone)\n",
    "df['review_date'] = pd.to_datetime(df['id'] // 1000, unit='s')\n",
    "df['review_date'] = df['review_date'].dt.tz_localize(\n",
    "    'UTC').dt.tz_convert(timezone)\n",
    "df.drop(df[df['review_date'].dt.year < 2006].index, inplace=True)\n",
    "df.sort_values(by=['cid', 'id'], inplace=True, ignore_index=True)\n",
    "type_sequence = np.array(df['type'])\n",
    "df.to_csv(\"revlog.csv\", index=False)\n",
    "print(\"revlog.csv saved.\")\n",
    "df = df[(df['type'] == 0) | (df['type'] == 1)].copy()\n",
    "df['real_days'] = df['review_date'] - timedelta(hours=next_day_starts_at)\n",
    "df['real_days'] = pd.DatetimeIndex(df['real_days'].dt.floor('D')).to_julian_date()\n",
    "df.drop_duplicates(['cid', 'real_days'], keep='first', inplace=True)\n",
    "df['delta_t'] = df.real_days.diff()\n",
    "df.dropna(inplace=True)\n",
    "df['delta_t'] = df['delta_t'].astype(dtype=int)\n",
    "df['i'] = 1\n",
    "df['r_history'] = \"\"\n",
    "df['t_history'] = \"\"\n",
    "col_idx = {key: i for i, key in enumerate(df.columns)}\n",
    "\n",
    "\n",
    "# code from https://github.com/L-M-Sherlock/anki_revlog_analysis/blob/main/revlog_analysis.py\n",
    "def get_feature(x):\n",
    "    for idx, log in enumerate(x.itertuples()):\n",
    "        if idx == 0:\n",
    "            x.iloc[idx, col_idx['delta_t']] = 0\n",
    "        if idx == x.shape[0] - 1:\n",
    "            break\n",
    "        x.iloc[idx + 1, col_idx['i']] = x.iloc[idx, col_idx['i']] + 1\n",
    "        x.iloc[idx + 1, col_idx['t_history']] = f\"{x.iloc[idx, col_idx['t_history']]},{x.iloc[idx, col_idx['delta_t']]}\"\n",
    "        x.iloc[idx + 1, col_idx['r_history']] = f\"{x.iloc[idx, col_idx['r_history']]},{x.iloc[idx, col_idx['r']]}\"\n",
    "    return x\n",
    "\n",
    "tqdm.notebook.tqdm.pandas()\n",
    "df = df.groupby('cid', as_index=False).progress_apply(get_feature)\n",
    "df[\"t_history\"] = df[\"t_history\"].map(lambda x: x[1:] if len(x) > 1 else x)\n",
    "df[\"r_history\"] = df[\"r_history\"].map(lambda x: x[1:] if len(x) > 1 else x)\n",
    "df.to_csv('revlog_history.tsv', sep=\"\\t\", index=False)\n",
    "print(\"Trainset saved.\")\n",
    "\n",
    "def cal_retention(group: pd.DataFrame) -> pd.DataFrame:\n",
    "    group['retention'] = round(group['r'].map(lambda x: {1: 0, 2: 1, 3: 1, 4: 1}[x]).mean(), 4)\n",
    "    group['total_cnt'] = group.shape[0]\n",
    "    return group\n",
    "\n",
    "df = df.groupby(by=['r_history', 'delta_t']).progress_apply(cal_retention)\n",
    "print(\"Retention calculated.\")\n",
    "df = df.drop(columns=['id', 'cid', 'usn', 'ivl', 'last_lvl', 'factor', 'time', 'type', 'create_date', 'review_date', 'real_days', 'r', 't_history'])\n",
    "df.drop_duplicates(inplace=True)\n",
    "df = df[(df['retention'] < 1) & (df['retention'] > 0)]\n",
    "\n",
    "def cal_stability(group: pd.DataFrame) -> pd.DataFrame:\n",
    "    if group['i'].values[0] > 1:\n",
    "        r_ivl_cnt = sum(group['delta_t'] * group['retention'].map(np.log) * pow(group['total_cnt'], 2))\n",
    "        ivl_ivl_cnt = sum(group['delta_t'].map(lambda x: x ** 2) * pow(group['total_cnt'], 2))\n",
    "        group['stability'] = round(np.log(0.9) / (r_ivl_cnt / ivl_ivl_cnt), 1)\n",
    "    else:\n",
    "        group['stability'] = 0.0\n",
    "    group['group_cnt'] = sum(group['total_cnt'])\n",
    "    group['avg_retention'] = round(sum(group['retention'] * pow(group['total_cnt'], 2)) / sum(pow(group['total_cnt'], 2)), 3)\n",
    "    group['avg_interval'] = round(sum(group['delta_t'] * pow(group['total_cnt'], 2)) / sum(pow(group['total_cnt'], 2)), 1)\n",
    "    del group['total_cnt']\n",
    "    del group['retention']\n",
    "    del group['delta_t']\n",
    "    return group\n",
    "\n",
    "df = df.groupby(by=['r_history']).progress_apply(cal_stability)\n",
    "print(\"Stability calculated.\")\n",
    "df.reset_index(drop = True, inplace = True)\n",
    "df.drop_duplicates(inplace=True)\n",
    "df.sort_values(by=['r_history'], inplace=True, ignore_index=True)\n",
    "\n",
    "if df.shape[0] > 0:\n",
    "    for idx in tqdm.notebook.tqdm(df.index):\n",
    "        item = df.loc[idx]\n",
    "        index = df[(df['i'] == item['i'] + 1) & (df['r_history'].str.startswith(item['r_history']))].index\n",
    "        df.loc[index, 'last_stability'] = item['stability']\n",
    "    df['factor'] = round(df['stability'] / df['last_stability'], 2)\n",
    "    df = df[(df['i'] >= 2) & (df['group_cnt'] >= 100)]\n",
    "    df['last_recall'] = df['r_history'].map(lambda x: x[-1])\n",
    "    df = df[df.groupby(['i', 'r_history'])['group_cnt'].transform(max) == df['group_cnt']]\n",
    "    df.to_csv('./stability_for_analysis.tsv', sep='\\t', index=None)\n",
    "    print(\"1:again, 2:hard, 3:good, 4:easy\\n\")\n",
    "    print(df[df['r_history'].str.contains(r'^[1-4][^124]*$', regex=True)][['r_history', 'avg_interval', 'avg_retention', 'stability', 'factor', 'group_cnt']].to_string(index=False))\n",
    "    print(\"Analysis saved!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "k_SgzC-auWmu"
   },
   "source": [
    "## 2 Optimize parameter"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "WrfBJjqCHEwJ"
   },
   "source": [
    "### 2.1 Define the model\n",
    "\n",
    "FSRS is a time-series model for predicting memory states."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "id": "tdYp3GMLhTYm"
   },
   "outputs": [],
   "source": [
    "init_w = [1, 1, 5, -0.5, -0.5, 0.2, 1.4, -0.02, 0.8, 2, -0.2, 0.5, 1]\n",
    "\n",
    "\n",
    "class FSRS(nn.Module):\n",
    "    def __init__(self, w):\n",
    "        super(FSRS, self).__init__()\n",
    "        self.w = nn.Parameter(torch.FloatTensor(w))\n",
    "        self.zero = torch.FloatTensor([0.0])\n",
    "\n",
    "    def forward(self, x, s, d):\n",
    "        '''\n",
    "        :param x: [review interval, review response]\n",
    "        :param s: stability\n",
    "        :param d: difficulty\n",
    "        :return:\n",
    "        '''\n",
    "        if torch.equal(s, self.zero):\n",
    "            # first learn, init memory states\n",
    "            new_s = self.w[0] + self.w[1] * (x[1] - 1)\n",
    "            new_d = self.w[2] + self.w[3] * (x[1] - 3)\n",
    "            new_d = new_d.clamp(1, 10)\n",
    "        else:\n",
    "            r = torch.exp(np.log(0.9) * x[0] / s)\n",
    "            new_d = d + self.w[4] * (x[1] - 3)\n",
    "            new_d = self.mean_reversion(self.w[2], new_d)\n",
    "            new_d = new_d.clamp(1, 10)\n",
    "            # recall\n",
    "            if x[1] > 1:\n",
    "                new_s = s * (1 + torch.exp(self.w[6]) *\n",
    "                             (11 - new_d) *\n",
    "                             torch.pow(s, self.w[7]) *\n",
    "                             (torch.exp((1 - r) * self.w[8]) - 1))\n",
    "            # forget\n",
    "            else:\n",
    "                new_s = self.w[9] * torch.pow(new_d, self.w[10]) * torch.pow(\n",
    "                    s, self.w[11]) * torch.exp((1 - r) * self.w[12])\n",
    "        return new_s, new_d\n",
    "\n",
    "    def loss(self, s, t, r):\n",
    "        return - (r * np.log(0.9) * t / s + (1 - r) * torch.log(1 - torch.exp(np.log(0.9) * t / s)))\n",
    "\n",
    "    def mean_reversion(self, init, current):\n",
    "        return self.w[5] * init + (1-self.w[5]) * current\n",
    "\n",
    "\n",
    "class WeightClipper(object):\n",
    "    def __init__(self, frequency=1):\n",
    "        self.frequency = frequency\n",
    "\n",
    "    def __call__(self, module):\n",
    "        if hasattr(module, 'w'):\n",
    "            w = module.w.data\n",
    "            w[0] = w[0].clamp(0.1, 10)  # initStability\n",
    "            w[1] = w[1].clamp(0.1, 5)  # initStabilityRatingFactor\n",
    "            w[2] = w[2].clamp(1, 10)  # initDifficulty\n",
    "            w[3] = w[3].clamp(-5, -0.1)  # initDifficultyRatingFactor\n",
    "            w[4] = w[4].clamp(-5, -0.1)  # updateDifficultyRatingFactor\n",
    "            w[5] = w[5].clamp(0, 0.5)  # difficultyMeanReversionFactor\n",
    "            w[6] = w[6].clamp(0, 2)  # recallFactor\n",
    "            w[7] = w[7].clamp(-0.2, -0.01)  # recallStabilityDecay\n",
    "            w[8] = w[8].clamp(0.01, 1.5)  # recallRetrievabilityFactor\n",
    "            w[9] = w[9].clamp(0.5, 5)  # forgetFactor\n",
    "            w[10] = w[10].clamp(-2, -0.01)  # forgetDifficultyDecay\n",
    "            w[11] = w[11].clamp(0.01, 0.9)  # forgetStabilityDecay\n",
    "            w[12] = w[12].clamp(0.01, 2)  # forgetRetrievabilityFactor\n",
    "            module.w.data = w\n",
    "\n",
    "def lineToTensor(line):\n",
    "    ivl = line[0].split(',')\n",
    "    response = line[1].split(',')\n",
    "    tensor = torch.zeros(len(response), 2)\n",
    "    for li, response in enumerate(response):\n",
    "        tensor[li][0] = int(ivl[li])\n",
    "        tensor[li][1] = int(response)\n",
    "    return tensor\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8E1dYfgQLZAC"
   },
   "source": [
    "### 2.2 Train the model\n",
    "\n",
    "The `revlog_history.tsv` generated before will be used for training the FSRS model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Jht0gneShowU",
    "outputId": "aaa72b79-b454-483b-d746-df1a353b2c8f"
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9fcd540afa254d6082b0f51400d633a4",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/225934 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tensorized!\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "8539e0a6cc3f4418859417f762a4b2cd",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "pre-train:   0%|          | 0/28972 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "w: [1.0138, 2.293, 5.0, -0.5, -0.5, 0.2, 1.4, -0.02, 0.8, 2.0, -0.2, 0.5, 1.0]\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "cc99188751a544b4a3481473dda3b179",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "train:   0%|          | 0/196962 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "iteration: 1\n",
      "w: [1.0138, 2.293, 4.9984, -0.4984, -0.4984, 0.2016, 1.4016, -0.0184, 0.8016, 2.0016, -0.1984, 0.5016, 1.0016]\n",
      "iteration: 19697\n",
      "w: [1.014, 2.2933, 5.1859, -0.8665, -0.753, 0.0278, 1.3077, -0.0323, 0.6998, 1.783, -0.4174, 0.4751, 0.7849]\n",
      "iteration: 39393\n",
      "w: [1.014, 2.2933, 5.1883, -1.0109, -0.8103, 0.0189, 1.3359, -0.0402, 0.722, 1.7791, -0.4218, 0.5329, 0.7656]\n",
      "iteration: 59089\n",
      "w: [1.014, 2.2933, 5.1806, -1.0338, -0.9271, 0.009, 1.3561, -0.0459, 0.734, 1.7582, -0.4392, 0.596, 0.8001]\n",
      "iteration: 78785\n",
      "w: [1.014, 2.2933, 5.231, -1.0983, -1.0567, 0.022, 1.4053, -0.0366, 0.7799, 1.7125, -0.4748, 0.6083, 0.7739]\n",
      "iteration: 98481\n",
      "w: [1.014, 2.2933, 5.1966, -1.0786, -1.1153, 0.005, 1.4282, -0.0441, 0.7988, 1.7388, -0.4457, 0.6353, 0.8087]\n",
      "iteration: 118177\n",
      "w: [1.014, 2.2933, 5.1881, -1.1304, -1.1087, 0.0283, 1.4025, -0.0234, 0.7683, 1.7037, -0.4725, 0.5728, 0.8558]\n",
      "iteration: 137873\n",
      "w: [1.014, 2.2933, 5.146, -1.1969, -1.0858, 0.0077, 1.388, -0.026, 0.746, 1.7052, -0.4699, 0.6312, 0.9203]\n",
      "iteration: 157569\n",
      "w: [1.014, 2.2933, 5.1197, -1.1527, -1.0874, 0.0259, 1.368, -0.0762, 0.7209, 1.7295, -0.4381, 0.6247, 0.9711]\n",
      "iteration: 177265\n",
      "w: [1.014, 2.2933, 5.0225, -1.1358, -1.0742, 0.0118, 1.4074, -0.0451, 0.7556, 1.7049, -0.461, 0.5968, 0.994]\n",
      "iteration: 196961\n",
      "w: [1.014, 2.2933, 4.9588, -1.1608, -0.9955, 0.0235, 1.3923, -0.0485, 0.7363, 1.6938, -0.4707, 0.6032, 0.9763]\n",
      "\n",
      "Training finished!\n"
     ]
    }
   ],
   "source": [
    "model = FSRS(init_w)\n",
    "clipper = WeightClipper()\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=5e-4)\n",
    "\n",
    "dataset = pd.read_csv(\"./revlog_history.tsv\", sep='\\t', index_col=None, dtype={'r_history': str ,'t_history': str} )\n",
    "dataset = dataset[(dataset['i'] > 1) & (dataset['delta_t'] > 0) & (dataset['t_history'].str.count(',0') == 0)]\n",
    "dataset['tensor'] = dataset.progress_apply(lambda x: lineToTensor(list(zip([x['t_history']], [x['r_history']]))[0]), axis=1)\n",
    "print(\"Tensorized!\")\n",
    "\n",
    "pre_train_set = dataset[dataset['i'] == 2]\n",
    "# pretrain\n",
    "epoch_len = len(pre_train_set)\n",
    "n_epoch = 1\n",
    "pbar = tqdm.notebook.tqdm(desc=\"pre-train\", colour=\"red\", total=epoch_len*n_epoch)\n",
    "\n",
    "for k in range(n_epoch):\n",
    "    for i, (_, row) in enumerate(shuffle(pre_train_set, random_state=2022 + k).iterrows()):\n",
    "        model.train()\n",
    "        optimizer.zero_grad()\n",
    "        output_t = [(model.zero, model.zero)]\n",
    "        for input_t in row['tensor']:\n",
    "            output_t.append(model(input_t, *output_t[-1]))\n",
    "        loss = model.loss(output_t[-1][0], row['delta_t'],\n",
    "                            {1: 0, 2: 1, 3: 1, 4: 1}[row['r']])\n",
    "        if np.isnan(loss.data.item()):\n",
    "            # Exception Case\n",
    "            print(row, output_t)\n",
    "            raise Exception('error case')\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        model.apply(clipper)\n",
    "        pbar.update()\n",
    "pbar.close()\n",
    "for name, param in model.named_parameters():\n",
    "    print(f\"{name}: {list(map(lambda x: round(float(x), 4),param))}\")\n",
    "\n",
    "train_set = dataset[dataset['i'] > 2]\n",
    "epoch_len = len(train_set)\n",
    "n_epoch = 1\n",
    "print_len = max(epoch_len*n_epoch // 10, 1)\n",
    "pbar = tqdm.notebook.tqdm(desc=\"train\", colour=\"red\", total=epoch_len*n_epoch)\n",
    "\n",
    "for k in range(n_epoch):\n",
    "    for i, (_, row) in enumerate(shuffle(train_set, random_state=2022 + k).iterrows()):\n",
    "        model.train()\n",
    "        optimizer.zero_grad()\n",
    "        output_t = [(model.zero, model.zero)]\n",
    "        for input_t in row['tensor']:\n",
    "            output_t.append(model(input_t, *output_t[-1]))\n",
    "        loss = model.loss(output_t[-1][0], row['delta_t'],\n",
    "                          {1: 0, 2: 1, 3: 1, 4: 1}[row['r']])\n",
    "        if np.isnan(loss.data.item()):\n",
    "            # Exception Case\n",
    "            print(row, output_t)\n",
    "            raise Exception('error case')\n",
    "        loss.backward()\n",
    "        for param in model.parameters():\n",
    "            param.grad[:2] = torch.zeros(2)\n",
    "        optimizer.step()\n",
    "        model.apply(clipper)\n",
    "        pbar.update()\n",
    "\n",
    "        if (k * epoch_len + i) % print_len == 0:\n",
    "            print(f\"iteration: {k * epoch_len + i + 1}\")\n",
    "            for name, param in model.named_parameters():\n",
    "                print(f\"{name}: {list(map(lambda x: round(float(x), 4),param))}\")\n",
    "pbar.close()\n",
    "\n",
    "w = list(map(lambda x: round(float(x), 4), dict(model.named_parameters())['w'].data))\n",
    "\n",
    "print(\"\\nTraining finished!\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "BZ4S2l7BWfzr"
   },
   "source": [
    "## 3 Result\n",
    "\n",
    "Copy the optimal parameters for FSRS for you in the output of next code cell after running."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "NTnPSDA2QpUu",
    "outputId": "49f487b9-69a7-4e96-b35a-7e027f478fbd"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "var w = [1.014, 2.2933, 4.9588, -1.1608, -0.9954, 0.0234, 1.3923, -0.0484, 0.7363, 1.6937, -0.4708, 0.6032, 0.9762];\n"
     ]
    }
   ],
   "source": [
    "print(f\"var w = {w};\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "I_zsoDyTaTrT"
   },
   "source": [
    "You can see the memory states and intervals generated by FSRS as if you press the good in each review at the due date scheduled by FSRS."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "iws4rtP1WKBT",
    "outputId": "890d0287-1a17-4c59-fbbf-ee54d79cd383"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1:again, 2:hard, 3:good, 4:easy\n",
      "\n",
      "first rating: 1\n",
      "rating history: 1,3,3,3,3,3,3,3,3,3,3\n",
      "interval history: 0,1,2,4,9,19,39,79,159,317,624\n",
      "difficulty history: 0,7.3,7.2,7.2,7.1,7.1,7.0,7.0,6.9,6.9,6.8\n",
      "\n",
      "first rating: 2\n",
      "rating history: 2,3,3,3,3,3,3,3,3,3,3\n",
      "interval history: 0,3,8,19,44,100,223,489,1052,2226,4631\n",
      "difficulty history: 0,6.1,6.1,6.1,6.0,6.0,6.0,6.0,5.9,5.9,5.9\n",
      "\n",
      "first rating: 3\n",
      "rating history: 3,3,3,3,3,3,3,3,3,3,3\n",
      "interval history: 0,6,16,42,107,265,641,1512,3483,7842,17280\n",
      "difficulty history: 0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0\n",
      "\n",
      "first rating: 4\n",
      "rating history: 4,3,3,3,3,3,3,3,3,3,3\n",
      "interval history: 0,8,24,69,192,517,1348,3409,8376,20022,46625\n",
      "difficulty history: 0,3.8,3.8,3.9,3.9,3.9,3.9,4.0,4.0,4.0,4.0\n",
      "\n"
     ]
    }
   ],
   "source": [
    "requestRetention = 0.9  # recommended setting: 0.8 ~ 0.9\n",
    "\n",
    "\n",
    "class Collection:\n",
    "    def __init__(self, w):\n",
    "        self.model = FSRS(w)\n",
    "\n",
    "    def states(self, t_history, r_history):\n",
    "        with torch.no_grad():\n",
    "            line_tensor = lineToTensor(list(zip([t_history], [r_history]))[0])\n",
    "            output_t = [(self.model.zero, self.model.zero)]\n",
    "            for input_t in line_tensor:\n",
    "                output_t.append(self.model(input_t, *output_t[-1]))\n",
    "            return output_t[-1]\n",
    "\n",
    "\n",
    "my_collection = Collection(w)\n",
    "print(\"1:again, 2:hard, 3:good, 4:easy\\n\")\n",
    "for first_rating in (1,2,3,4):\n",
    "    print(f'first rating: {first_rating}')\n",
    "    t_history = \"0\"\n",
    "    d_history = \"0\"\n",
    "    r_history = f\"{first_rating}\"  # the first rating of the new card\n",
    "    # print(\"stability, difficulty, lapses\")\n",
    "    for i in range(10):\n",
    "        states = my_collection.states(t_history, r_history)\n",
    "        # print('{0:9.2f} {1:11.2f} {2:7.0f}'.format(\n",
    "            # *list(map(lambda x: round(float(x), 4), states))))\n",
    "        next_t = max(round(float(np.log(requestRetention)/np.log(0.9) * states[0])), 1)\n",
    "        difficulty = round(float(states[1]), 1)\n",
    "        t_history += f',{int(next_t)}'\n",
    "        d_history += f',{difficulty}'\n",
    "        r_history += f\",3\"\n",
    "    print(f\"rating history: {r_history}\")\n",
    "    print(f\"interval history: {t_history}\")\n",
    "    print(f\"difficulty history: {d_history}\")\n",
    "    print('')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can change the `test_rating_sequence` to see the scheduling intervals in different ratings."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(tensor(5.6006), tensor(4.9588))\n",
      "(tensor(15.8420), tensor(4.9588))\n",
      "(tensor(41.8382), tensor(4.9588))\n",
      "(tensor(106.9516), tensor(4.9588))\n",
      "(tensor(265.4778), tensor(4.9588))\n",
      "(tensor(21.7929), tensor(6.9030))\n",
      "(tensor(4.3071), tensor(8.8017))\n",
      "(tensor(6.9323), tensor(8.7118))\n",
      "(tensor(11.5881), tensor(8.6240))\n",
      "(tensor(19.6509), tensor(8.5382))\n",
      "(tensor(33.1994), tensor(8.4545))\n",
      "(tensor(55.7034), tensor(8.3727))\n",
      "rating history: 3,3,3,3,3,1,1,3,3,3,3,3\n",
      "interval history: 0,6,16,42,107,265,22,4,7,12,20,33,56\n",
      "difficulty history: 0,5.0,5.0,5.0,5.0,5.0,6.9,8.8,8.7,8.6,8.5,8.5,8.4\n"
     ]
    }
   ],
   "source": [
    "test_rating_sequence = \"3,3,3,3,3,1,1,3,3,3,3,3\"\n",
    "requestRetention = 0.9  # recommended setting: 0.8 ~ 0.9\n",
    "easyBonus = 1.3\n",
    "hardInterval = 1.2\n",
    "\n",
    "t_history = \"0\"\n",
    "d_history = \"0\"\n",
    "for i in range(len(test_rating_sequence.split(','))):\n",
    "    rating = test_rating_sequence[2*i]\n",
    "    last_t = int(t_history.split(',')[-1])\n",
    "    r_history = test_rating_sequence[:2*i+1]\n",
    "    states = my_collection.states(t_history, r_history)\n",
    "    print(states)\n",
    "    next_t = max(1,round(float(np.log(requestRetention)/np.log(0.9) * states[0])))\n",
    "    if rating == '4':\n",
    "        next_t = round(next_t * easyBonus)\n",
    "    elif rating == '2':\n",
    "        next_t = round(last_t * hardInterval)\n",
    "    t_history += f',{int(next_t)}'\n",
    "    difficulty = round(float(states[1]), 1)\n",
    "    d_history += f',{difficulty}'\n",
    "print(f\"rating history: {test_rating_sequence}\")\n",
    "print(f\"interval history: {t_history}\")\n",
    "print(f\"difficulty history: {d_history}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Predict memory states for each review and save them in `prediction.tsv`.\n",
    "\n",
    "Meanwhile, it will count the distribution of difficulty."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "0bc168078d174ab88d48a1a24056bd7f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/119670 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "prediction.tsv saved.\n",
      "difficulty\n",
      "1     0.001868\n",
      "2     0.011008\n",
      "3     0.039538\n",
      "4     0.154465\n",
      "5     0.160835\n",
      "6     0.067444\n",
      "7     0.135070\n",
      "8     0.068684\n",
      "9     0.107407\n",
      "10    0.253680\n",
      "Name: count, dtype: float64\n"
     ]
    }
   ],
   "source": [
    "def predict_memory_states(group):\n",
    "    states = my_collection.states(*group.name)\n",
    "    group['stability'] = float(states[0])\n",
    "    group['difficulty'] = float(states[1])\n",
    "    group['count'] = len(group)\n",
    "    return pd.DataFrame({\n",
    "        'r_history': [group.name[1]], \n",
    "        't_history': [group.name[0]], \n",
    "        'stability': [round(float(states[0]),2)], \n",
    "        'difficulty': [round(float(states[1]),2)], \n",
    "        'count': [len(group)] \n",
    "    })\n",
    "\n",
    "prediction = dataset.groupby(by=['t_history', 'r_history']).progress_apply(predict_memory_states)\n",
    "prediction.reset_index(drop=True, inplace=True)\n",
    "prediction.sort_values(by=['r_history'], inplace=True)\n",
    "prediction.to_csv(\"./prediction.tsv\", sep='\\t', index=None)\n",
    "print(\"prediction.tsv saved.\")\n",
    "prediction['difficulty'] = prediction['difficulty'].map(lambda x: int(round(x)))\n",
    "difficulty_distribution = prediction.groupby(by=['difficulty'])['count'].sum() / prediction['count'].sum()\n",
    "print(difficulty_distribution)\n",
    "difficulty_distribution_padding = np.zeros(10)\n",
    "for i in range(10):\n",
    "    if i+1 in difficulty_distribution.index:\n",
    "        difficulty_distribution_padding[i] = difficulty_distribution.loc[i+1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Calculate the optimal retention to minimize the repetitions for long-term memory consolidation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "terminal stability:  637.63\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b4045c6a90614c77838aa75bdd3c9185",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/13 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "expected_repetitions.csv saved.\n",
      "\n",
      "-----suggested retention: 0.85-----\n"
     ]
    },
    {
     "data": {
      "image/png": "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iqXDgraPLMvow4zow4zgX9yoeL0+j4/D4RNATod/zCeIsPqqIQfn+4ShCzMga0S+j+DaxOtxc6rwMEV5+znhb0xsO1NaZ54v3+Z6MgbeQKo/30ZwiQUDU1NTeemll5raljZDWq84fvHs9RzefprD209TeszGibyznMg7y3efH6RdBzOd/KInJilcfHgLrhlkjQZDuClQJFFVVbweDx5/uMvtcOJ2OVAVhdt++l/06N6NF56Z5ttXqw0WPwaDyPcRtEmqKs5y0i9oTubtoyT/EB63K2iOJMtYOnYiKbMr7bO6kdylG+b4duL7pB4uSeisW7eOd955h8OHD/OPf/yD5ORkPv74Y9LT07npppua2sZWhyRJxCVHEJccwXXj0rGWVlOwo5T8bacoyq/g9NFKTh+tZOP/O0x0Qjid+sbTqa8FS5oZSRZ/pIJrB0mS0Op0aHU6wvyudVVV8bhcaPU6tHo9WoMBj8uJ4vHg9HiC8330+oD40RrC0On1gXyf3/3ud3z//ffs3r2bbt26sX379jrn37lzJzk5OWzevJl27drxyCOP8Mc//vGqXPv5rFmzhscee4w9e/aQmprKM888c9EeXN988w0zZsxgz549hIWFMWTIEF577TU6dux4VWwWXD6K4qX06BFO5u2nKG8fJ/P2c7akqM68sAgz7bt09dfn6kpiRhd0VzkXr7USstD54osvuO+++/jlL3/J1q1bcTqdAFRUVPDSSy9dsJ/LtUpkvJE+w1PpMzyVKquLwp2lHN5+mmP7yzhbUsXWb46y9ZujmKINdOoTT3q/drTPjEajEQmagmsPSZL83hotBmM48SkdfPk+znOJzm6n05fv43Lhcbmorqyd72NAF2bA43Ix4f77+XHLFnbu3FnnPFarlVGjRjFixAjefvttdu3axcSJE4mOjubhhx++ZPtdLhd6fWg5eTVdySdPnswnn3zCypUreeihh0hKSmL06NEN7nPHHXfw2GOP8cknn1BRUcGjjz7KXXfdxdatWy/ZfsGVxWGzUXRwPycP7ufkgX0UHcoLqmUDgCQRn9KB9l26keQXNzFJ7YW35hIJWej86U9/4u233+b+++/n73//e2B88ODB/OlPf2pS49oi4ZF6ut/Unu43tcdV7eHInjMc3n6aI7vPYD/rZNfaE+xaewJDuJaOvePp1Lcdqd1j0emFi14QOqqq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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "base = 1.01\n",
    "index_len = 800\n",
    "index_offset = 150\n",
    "d_range = 10\n",
    "d_offset = 1\n",
    "r_repetitions = 1\n",
    "f_repetitions = 2.3\n",
    "max_repetitions = 200000\n",
    "\n",
    "type_block = dict()\n",
    "type_count = dict()\n",
    "last_t = type_sequence[0]\n",
    "type_block[last_t] = 1\n",
    "type_count[last_t] = 1\n",
    "for t in type_sequence[1:]:\n",
    "    type_count[t] = type_count.setdefault(t, 0) + 1\n",
    "    if t != last_t:\n",
    "        type_block[t] = type_block.setdefault(t, 0) + 1\n",
    "    last_t = t\n",
    "if 2 in type_count and 2 in type_block:\n",
    "    f_repetitions = round(type_count[2]/type_block[2] + 1, 1)\n",
    "\n",
    "def stability2index(stability):\n",
    "    return int(round(np.log(stability) / np.log(base)) + index_offset)\n",
    "\n",
    "def init_stability(d):\n",
    "    return max(((d - w[2]) / w[3] + 2) * w[1] + w[0], np.power(base, -index_offset))\n",
    "\n",
    "def cal_next_recall_stability(s, r, d, response):\n",
    "    if response == 1:\n",
    "        return s * (1 + np.exp(w[6]) * (11 - d) * np.power(s, w[7]) * (np.exp((1 - r) * w[8]) - 1))\n",
    "    else:\n",
    "        return w[9] * np.power(d, w[10]) * np.power(s, w[11]) * np.exp((1 - r) * w[12])\n",
    "\n",
    "\n",
    "stability_list = np.array([np.power(base, i - index_offset) for i in range(index_len)])\n",
    "print(f\"terminal stability: {stability_list.max(): .2f}\")\n",
    "df = pd.DataFrame(columns=[\"retention\", \"difficulty\", \"repetitions\"])\n",
    "\n",
    "for percentage in tqdm.notebook.tqdm(range(96, 70, -2)):\n",
    "    recall = percentage / 100\n",
    "    repetitions_list = np.zeros((d_range, index_len))\n",
    "    repetitions_list[:,:-1] = max_repetitions\n",
    "    for d in range(d_range, 0, -1):\n",
    "        s0 = init_stability(d)\n",
    "        s0_index = stability2index(s0)\n",
    "        diff = max_repetitions\n",
    "        while diff > 0.1:\n",
    "            s0_repetitions = repetitions_list[d - 1][s0_index]\n",
    "            for s_index in range(index_len - 2, -1, -1):\n",
    "                stability = stability_list[s_index];\n",
    "                interval = max(1, round(stability * np.log(recall) / np.log(0.9)))\n",
    "                p_recall = np.power(0.9, interval / stability)\n",
    "                recall_s = cal_next_recall_stability(stability, p_recall, d, 1)\n",
    "                forget_d = min(d + d_offset, 10)\n",
    "                forget_s = cal_next_recall_stability(stability, p_recall, forget_d, 0)\n",
    "                recall_s_index = min(stability2index(recall_s), index_len - 1)\n",
    "                forget_s_index = min(max(stability2index(forget_s), 0), index_len - 1)\n",
    "                recall_repetitions = repetitions_list[d - 1][recall_s_index] + r_repetitions\n",
    "                forget_repetitions = repetitions_list[forget_d - 1][forget_s_index] + f_repetitions\n",
    "                exp_repetitions = p_recall * recall_repetitions + (1.0 - p_recall) * forget_repetitions\n",
    "                if exp_repetitions < repetitions_list[d - 1][s_index]:\n",
    "                    repetitions_list[d - 1][s_index] = exp_repetitions\n",
    "            diff = s0_repetitions - repetitions_list[d - 1][s0_index]\n",
    "        df.loc[0 if pd.isnull(df.index.max()) else df.index.max() + 1] = [recall, d, s0_repetitions]\n",
    "\n",
    "df.sort_values(by=[\"difficulty\", \"retention\"], inplace=True)\n",
    "df.to_csv(\"./expected_repetitions.csv\", index=False)\n",
    "print(\"expected_repetitions.csv saved.\")\n",
    "\n",
    "optimal_retention_list = np.zeros(10)\n",
    "for d in range(1, d_range+1):\n",
    "    retention = df[df[\"difficulty\"] == d][\"retention\"]\n",
    "    repetitions = df[df[\"difficulty\"] == d][\"repetitions\"]\n",
    "    optimal_retention = retention.iat[repetitions.argmin()]\n",
    "    optimal_retention_list[d-1] = optimal_retention\n",
    "    plt.plot(retention, repetitions, label=f\"d={d}, r={optimal_retention}\")\n",
    "print(f\"\\n-----suggested retention: {np.inner(difficulty_distribution_padding, optimal_retention_list):.2f}-----\")\n",
    "plt.ylabel(\"expected repetitions\")\n",
    "plt.xlabel(\"retention\")\n",
    "plt.legend()\n",
    "plt.grid()\n",
    "plt.semilogy()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Evaluate the model with the log loss. It will compare the log loss between initial model and trained model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "6dd615097589494b9829477848785fcb",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/225934 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loss before training: 0.3541\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "47fa4379ac954b9b810af3afdab10cea",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/225934 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loss after training: 0.3173\n"
     ]
    }
   ],
   "source": [
    "def log_loss(row):\n",
    "    states = my_collection.states(row['t_history'], row['r_history'])\n",
    "    row['log_loss'] = float(my_collection.model.loss(states[0], row['delta_t'], {1: 0, 2: 1, 3: 1, 4: 1}[row['r']]))\n",
    "    return row\n",
    "\n",
    "my_collection = Collection(init_w)\n",
    "dataset = dataset.progress_apply(log_loss, axis=1)\n",
    "print(f\"Loss before training: {dataset['log_loss'].mean():.4f}\")\n",
    "my_collection = Collection(w)\n",
    "dataset = dataset.progress_apply(log_loss, axis=1)\n",
    "print(f\"Loss after training: {dataset['log_loss'].mean():.4f}\")"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "authorship_tag": "ABX9TyMnk8/Ih2JAJZJ1PBkXQUBC",
   "collapsed_sections": [],
   "provenance": [],
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3.8.13 ('fsrs4anki')",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.13 | packaged by conda-forge | (default, Mar 25 2022, 06:05:16) \n[Clang 12.0.1 ]"
  },
  "vscode": {
   "interpreter": {
    "hash": "8dd9a290ffd10997e0b0d411ff1325a47862ea932e0fd309ade800e0e51d2b4b"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}