blob: 5cbca921278572b057cf13b56909293a4033077c (
about) (
plain)
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
|
;;; gnosis-algorithm.el --- Spaced Repetition Algorithm for Gnosis -*- lexical-binding: t; -*-
;; Copyright (C) 2023 Thanos Apollo
;; Author: Thanos Apollo <[email protected]>
;; Keywords: extensions
;; URL: https://git.thanosapollo.org/gnosis
;; Version: 0.0.1
;; Package-Requires: ((emacs "27.2") (compat "29.1.4.2"))
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Work in progress
;;; Code:
(require 'cl-lib)
(require 'calendar)
(defcustom gnosis-interval '(1 3)
"Gnosis initial interval.
Interval by which a new question is displayed or when it's ef is at 1.3.
First item: First interval
Second item: Second interval."
:group 'gnosis
:type 'list)
(defcustom gnosis-algorithm-ef '(0.3 0.3)
"Gnosis easiness factor.
First item : Increase factor
Second item: Decrease factor"
:group 'gnosis
:type 'list)
(defcustom gnosis-algorithm-ff 0.5
"Gnosis forgetting factor.
Used to calcuate new interval for failed questions."
:group 'gnosis
:type 'float)
(defun gnosis-algorithm-date (&optional offset)
"Return the current date in a list (year month day).
Optional integer OFFSET is a number of days from the current date."
(let* ((now (decode-time))
(now (list (decoded-time-month now)
(decoded-time-day now)
(decoded-time-year now))))
(let ((date (if (zerop (or offset 0))
now
(calendar-gregorian-from-absolute
(+ offset (calendar-absolute-from-gregorian now))))))
(list (nth 2 date) (nth 0 date) (nth 1 date)))))
(defun gnosis-algorithm-date-diff (year month day)
"Find the difference between the current date and the given date.
The structure of the given date is (YEAR MONTH DAY)."
(let ((current-date (gnosis-algorithm-date))
(given-date (encode-time 0 0 0 day month year)))
(- (time-to-days (current-time))
(time-to-days given-date))))
(defun gnosis-algorithm-e-factor (ef quality)
"Calculate new e-factor given existing EF and binary QUALITY, 0 or 1."
(cond
((not (numberp quality))
(error "Invalid argument passed to gnosis-algorithm-e-factor"))
((= quality 0) ;; If the quality score is 0 (fail), decrease the ef by a small penalty
(max 1.3 (- ef (cadr gnosis-ef))))
((= quality 1) ;; If the quality score is 1 (pass), increase the ef by a small reward
(+ ef (car gnosis-ef)))
(t (error "Invalid quality score passed to gnosis-algorithm-e-factor"))))
(defun gnosis-algorithm-next-interval (last-interval n ef success ff)
"Calculate next interval.
- LAST-INTERVAL : The number of days since the item was last reviewed.
- N : Number of times the item has been reviewed.
- EF : Easiness Factor.
- SUCCESS : Success of the recall, ranges from 0 (unsuccessful) to 1
(successful).
- FF: Failure factor
Returns a tuple: (INTERVAL N EF) where,
- INTERVAL : The number of days until the item should next be reviewed.
- N : Incremented by 1.
- EF : Modified based on the recall success for the item."
(cl-assert (and (>= success 0)
(<= success 1)))
;; Calculate the next easiness factor.
(let* ((next-ef (gnosis-algorithm-e-factor ef success))
;; Calculate the next interval.
(interval
(cond
;; Show item same day on the first review
((= n 0) 0)
;; Immediately next day if it's the first time review.
((<= n 1) (car gnosis-interval))
;; After 3 days if it's second review.
((= n 2) (cadr gnosis-interval))
;; Increase last interval by 1 if recall was successful. Keep last interval if unsuccessful.
(t (if (= success 1)
(* ef last-interval)
(* ff last-interval))))))
(list (round interval) (1+ n) next-ef)))
(provide 'gnosis-algorithm)
;;; gnosis-algorithm.el ends here
|