ts-fsrs 2.2.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/default.d.ts +0 -4
- package/dist/default.js +4 -13
- package/dist/fsrs.d.ts +24 -17
- package/dist/fsrs.js +48 -35
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -3
- package/dist/models.d.ts +5 -7
- package/dist/models.js +4 -4
- package/dist/scheduler.d.ts +4 -4
- package/dist/type.d.ts +0 -2
- package/package.json +1 -1
package/dist/default.d.ts
CHANGED
|
@@ -3,16 +3,12 @@ import { EnvParams } from "./type";
|
|
|
3
3
|
export declare const envParams: EnvParams;
|
|
4
4
|
export declare const default_request_retention: number;
|
|
5
5
|
export declare const default_maximum_interval: number;
|
|
6
|
-
export declare const default_easy_bonus: number;
|
|
7
|
-
export declare const default_hard_factor: number;
|
|
8
6
|
export declare const default_w: number[];
|
|
9
7
|
export declare const default_enable_fuzz: boolean;
|
|
10
8
|
export declare const FSRSVersion: string;
|
|
11
9
|
export declare const generatorParameters: (props?: Partial<FSRSParameters>) => {
|
|
12
10
|
request_retention: number;
|
|
13
11
|
maximum_interval: number;
|
|
14
|
-
easy_bonus: number;
|
|
15
|
-
hard_factor: number;
|
|
16
12
|
w: number[];
|
|
17
13
|
enable_fuzz: boolean;
|
|
18
14
|
};
|
package/dist/default.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.fsrs = exports.createEmptyCard = exports.generatorParameters = exports.FSRSVersion = exports.default_enable_fuzz = exports.default_w = exports.
|
|
6
|
+
exports.fsrs = exports.createEmptyCard = exports.generatorParameters = exports.FSRSVersion = exports.default_enable_fuzz = exports.default_w = exports.default_maximum_interval = exports.default_request_retention = exports.envParams = void 0;
|
|
7
7
|
const index_1 = require("./index");
|
|
8
8
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
9
9
|
dotenv_1.default.config({ path: `./.env.local` });
|
|
@@ -13,8 +13,6 @@ dotenv_1.default.config({ path: `./.env.development` });
|
|
|
13
13
|
exports.envParams = {
|
|
14
14
|
FSRS_REQUEST_RETENTION: Number(process.env.FSRS_REQUEST_RETENTION),
|
|
15
15
|
FSRS_MAXIMUM_INTERVAL: Number(process.env.FSRS_MAXIMUM_INTERVAL),
|
|
16
|
-
FSRS_EASY_BOUND: Number(process.env.FSRS_EASY_BOUND),
|
|
17
|
-
FSRS_HARD_FACTOR: Number(process.env.FSRS_HARD_FACTOR),
|
|
18
16
|
FSRS_W: process.env.FSRS_W
|
|
19
17
|
? JSON.parse(process.env.FSRS_W)
|
|
20
18
|
: undefined,
|
|
@@ -26,23 +24,16 @@ exports.default_request_retention = !isNaN(exports.envParams.FSRS_REQUEST_RETENT
|
|
|
26
24
|
exports.default_maximum_interval = !isNaN(exports.envParams.FSRS_MAXIMUM_INTERVAL)
|
|
27
25
|
? exports.envParams.FSRS_MAXIMUM_INTERVAL
|
|
28
26
|
: 36500;
|
|
29
|
-
exports.default_easy_bonus = !isNaN(exports.envParams.FSRS_EASY_BOUND)
|
|
30
|
-
? exports.envParams.FSRS_EASY_BOUND
|
|
31
|
-
: 1.3;
|
|
32
|
-
exports.default_hard_factor = !isNaN(exports.envParams.FSRS_HARD_FACTOR)
|
|
33
|
-
? exports.envParams.FSRS_HARD_FACTOR
|
|
34
|
-
: 1.2;
|
|
35
27
|
exports.default_w = exports.envParams.FSRS_W || [
|
|
36
|
-
|
|
28
|
+
0.4, 0.6, 2.4, 5.8, 4.93, 0.94, 0.86, 0.01, 1.49, 0.14, 0.94, 2.18, 0.05,
|
|
29
|
+
0.34, 1.26, 0.29, 2.61,
|
|
37
30
|
];
|
|
38
31
|
exports.default_enable_fuzz = exports.envParams.FSRS_ENABLE_FUZZ || false;
|
|
39
|
-
exports.FSRSVersion = "
|
|
32
|
+
exports.FSRSVersion = "3.0.0";
|
|
40
33
|
const generatorParameters = (props) => {
|
|
41
34
|
return {
|
|
42
35
|
request_retention: props?.request_retention || exports.default_request_retention,
|
|
43
36
|
maximum_interval: props?.maximum_interval || exports.default_maximum_interval,
|
|
44
|
-
easy_bonus: props?.easy_bonus || exports.default_easy_bonus,
|
|
45
|
-
hard_factor: props?.hard_factor || exports.default_hard_factor,
|
|
46
37
|
w: props?.w || exports.default_w,
|
|
47
38
|
enable_fuzz: props?.enable_fuzz || exports.default_enable_fuzz,
|
|
48
39
|
};
|
package/dist/fsrs.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare class FSRS {
|
|
|
7
7
|
private seed?;
|
|
8
8
|
constructor(param: Partial<FSRSParameters>);
|
|
9
9
|
repeat: (card: Card, now: Date) => {
|
|
10
|
-
|
|
10
|
+
1: {
|
|
11
11
|
card: Card;
|
|
12
12
|
log: {
|
|
13
13
|
rating: Rating;
|
|
@@ -17,7 +17,7 @@ export declare class FSRS {
|
|
|
17
17
|
review: Date;
|
|
18
18
|
};
|
|
19
19
|
};
|
|
20
|
-
|
|
20
|
+
2: {
|
|
21
21
|
card: Card;
|
|
22
22
|
log: {
|
|
23
23
|
rating: Rating;
|
|
@@ -27,7 +27,7 @@ export declare class FSRS {
|
|
|
27
27
|
review: Date;
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
|
-
|
|
30
|
+
3: {
|
|
31
31
|
card: Card;
|
|
32
32
|
log: {
|
|
33
33
|
rating: Rating;
|
|
@@ -37,7 +37,7 @@ export declare class FSRS {
|
|
|
37
37
|
review: Date;
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
|
-
|
|
40
|
+
4: {
|
|
41
41
|
card: Card;
|
|
42
42
|
log: {
|
|
43
43
|
rating: Rating;
|
|
@@ -60,28 +60,34 @@ export declare class FSRS {
|
|
|
60
60
|
next_ds(s: SchedulingCard, last_d: number, last_s: number, retrievability: number): void;
|
|
61
61
|
/**
|
|
62
62
|
* The formula used is :
|
|
63
|
-
* $$S_0(G) =
|
|
63
|
+
* $$S_0(G) = w_{G-1}$$
|
|
64
64
|
* $$\max \{S_0,0.1\}$$
|
|
65
|
-
* @param g Grade (rating at Anki) [
|
|
65
|
+
* @param g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]
|
|
66
66
|
* @return Stability (interval when R=90%)
|
|
67
67
|
*/
|
|
68
68
|
init_stability(g: number): number;
|
|
69
69
|
/**
|
|
70
70
|
* The formula used is :
|
|
71
|
-
* $$D_0(G) =
|
|
71
|
+
* $$D_0(G) = w_4 - (G-3) \cdot w_5$$
|
|
72
72
|
* $$\min \{\max \{D_0(G),1\},10\}$$
|
|
73
|
-
*
|
|
73
|
+
* where the D_0(3)=w_4 when the first rating is good.
|
|
74
|
+
* @param g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]
|
|
74
75
|
* @return Difficulty D \in [1,10]
|
|
75
76
|
*/
|
|
76
77
|
init_difficulty(g: number): number;
|
|
77
78
|
apply_fuzz(ivl: number): number;
|
|
79
|
+
/**
|
|
80
|
+
* Ref:
|
|
81
|
+
* constructor(param: Partial<FSRSParameters>)
|
|
82
|
+
* this.intervalModifier = 9 * (1 / this.param.request_retention - 1);
|
|
83
|
+
*/
|
|
78
84
|
next_interval(s: number): int;
|
|
79
85
|
/**
|
|
80
86
|
* The formula used is :
|
|
81
|
-
* $$next_d = D
|
|
87
|
+
* $$next_d = D - w_6 \cdot (R - 2)$$
|
|
82
88
|
* $$D^\prime(D,R) = w_5 \cdot D_0(2) +(1 - w_5) \cdot next_d$$
|
|
83
89
|
* @param d
|
|
84
|
-
* @param g Grade (
|
|
90
|
+
* @param g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]
|
|
85
91
|
* @return next_D
|
|
86
92
|
*/
|
|
87
93
|
next_difficulty(d: number, g: number): number;
|
|
@@ -92,24 +98,25 @@ export declare class FSRS {
|
|
|
92
98
|
constrain_difficulty(difficulty: number): number;
|
|
93
99
|
/**
|
|
94
100
|
* The formula used is :
|
|
95
|
-
* $$
|
|
96
|
-
* @param init $$w_2 : D_0(
|
|
97
|
-
* @param current $$D
|
|
101
|
+
* $$w_7 \cdot init +(1 - w_7) \cdot current$$
|
|
102
|
+
* @param init $$w_2 : D_0(3) = w_2 + (R-2) \cdot w_3= w_2$$
|
|
103
|
+
* @param current $$D - w_6 \cdot (R - 2)$$
|
|
98
104
|
* @return difficulty
|
|
99
105
|
*/
|
|
100
106
|
mean_reversion(init: number, current: number): number;
|
|
101
107
|
/**
|
|
102
108
|
* The formula used is :
|
|
103
|
-
* $$S^\prime_r(D,S,R) = S\cdot(e^{
|
|
109
|
+
* $$S^\prime_r(D,S,R,G) = S\cdot(e^{w_8}\cdot (11-D)\cdot S^{-w_9}\cdot(e^{w_10\cdot(1-R)}-1)\cdot w_15(if G=2) \cdot w_16(if G=4)+1)$$
|
|
104
110
|
* @param d Difficulty D \in [1,10]
|
|
105
111
|
* @param s Stability (interval when R=90%)
|
|
106
112
|
* @param r Retrievability (probability of recall)
|
|
113
|
+
* @param g Grade (Rating[0.again,1.hard,2.good,3.easy])
|
|
107
114
|
* @return S^\prime_r new stability after recall
|
|
108
115
|
*/
|
|
109
|
-
next_recall_stability(d: number, s: number, r: number): number;
|
|
116
|
+
next_recall_stability(d: number, s: number, r: number, g: Rating): number;
|
|
110
117
|
/**
|
|
111
118
|
* The formula used is :
|
|
112
|
-
* $$S^\prime_f(D,S,R) =
|
|
119
|
+
* $$S^\prime_f(D,S,R) = w_11\cdot D^{-w_{12}}\cdot ((S+1)^{w_{13}}-1) \cdot e^{w_{14}\cdot(1-R)}.$$
|
|
113
120
|
* @param d Difficulty D \in [1,10]
|
|
114
121
|
* @param s Stability (interval when R=90%)
|
|
115
122
|
* @param r Retrievability (probability of recall)
|
|
@@ -118,7 +125,7 @@ export declare class FSRS {
|
|
|
118
125
|
next_forget_stability(d: number, s: number, r: number): number;
|
|
119
126
|
/**
|
|
120
127
|
* The formula used is :
|
|
121
|
-
* $$R(t,S) =
|
|
128
|
+
* $$R(t,S) = (1 + \frac{t}{9 \cdot S})^{-1},$$
|
|
122
129
|
* @param t t days since the last review
|
|
123
130
|
* @param s Stability (interval when R=90%)
|
|
124
131
|
* @return r Retrievability (probability of recall)
|
package/dist/fsrs.js
CHANGED
|
@@ -8,14 +8,16 @@ const seedrandom_1 = __importDefault(require("seedrandom"));
|
|
|
8
8
|
const index_1 = require("./index");
|
|
9
9
|
const help_1 = require("./help");
|
|
10
10
|
const models_1 = require("./models");
|
|
11
|
+
// Ref: https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-v4
|
|
11
12
|
class FSRS {
|
|
12
13
|
param;
|
|
13
14
|
intervalModifier;
|
|
14
15
|
seed;
|
|
15
16
|
constructor(param) {
|
|
16
17
|
this.param = (0, index_1.generatorParameters)(param);
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
// Ref: https://github.com/open-spaced-repetition/py-fsrs/blob/ecd68e453611eb808c7367c7a5312d7cadeedf5c/src/fsrs/fsrs.py#L79
|
|
19
|
+
// The formula used is : I(r,s)=9 \cdot s \cdot (\frac{1}{r}-1)
|
|
20
|
+
this.intervalModifier = 9 * (1 / this.param.request_retention - 1);
|
|
19
21
|
}
|
|
20
22
|
repeat = (card, now) => {
|
|
21
23
|
card = {
|
|
@@ -37,7 +39,7 @@ class FSRS {
|
|
|
37
39
|
s.again.due = now.scheduler(1);
|
|
38
40
|
s.hard.due = now.scheduler(5);
|
|
39
41
|
s.good.due = now.scheduler(10);
|
|
40
|
-
easy_interval = this.next_interval(s.easy.stability
|
|
42
|
+
easy_interval = this.next_interval(s.easy.stability);
|
|
41
43
|
s.easy.scheduled_days = easy_interval;
|
|
42
44
|
s.easy.due = now.scheduler(easy_interval, true);
|
|
43
45
|
break;
|
|
@@ -45,7 +47,7 @@ class FSRS {
|
|
|
45
47
|
case models_1.State.Relearning:
|
|
46
48
|
hard_interval = 0;
|
|
47
49
|
good_interval = this.next_interval(s.good.stability);
|
|
48
|
-
easy_interval = Math.max(this.next_interval(s.easy.stability
|
|
50
|
+
easy_interval = Math.max(this.next_interval(s.easy.stability), good_interval + 1);
|
|
49
51
|
s.schedule(now, hard_interval, good_interval, easy_interval);
|
|
50
52
|
break;
|
|
51
53
|
case models_1.State.Review: {
|
|
@@ -54,11 +56,11 @@ class FSRS {
|
|
|
54
56
|
const last_s = card.stability;
|
|
55
57
|
const retrievability = this.current_retrievability(interval, last_s);
|
|
56
58
|
this.next_ds(s, last_d, last_s, retrievability);
|
|
57
|
-
hard_interval = this.next_interval(
|
|
59
|
+
hard_interval = this.next_interval(s.hard.stability);
|
|
58
60
|
good_interval = this.next_interval(s.good.stability);
|
|
59
61
|
hard_interval = Math.min(hard_interval, good_interval);
|
|
60
62
|
good_interval = Math.max(good_interval, hard_interval + 1);
|
|
61
|
-
easy_interval = Math.max(this.next_interval(s.easy.stability
|
|
63
|
+
easy_interval = Math.max(this.next_interval(s.easy.stability), good_interval + 1);
|
|
62
64
|
s.schedule(now, hard_interval, good_interval, easy_interval);
|
|
63
65
|
break;
|
|
64
66
|
}
|
|
@@ -93,31 +95,32 @@ class FSRS {
|
|
|
93
95
|
s.again.difficulty = this.next_difficulty(last_d, models_1.Rating.Again);
|
|
94
96
|
s.again.stability = this.next_forget_stability(s.again.difficulty, last_s, retrievability);
|
|
95
97
|
s.hard.difficulty = this.next_difficulty(last_d, models_1.Rating.Hard);
|
|
96
|
-
s.hard.stability = this.next_recall_stability(s.hard.difficulty, last_s, retrievability);
|
|
98
|
+
s.hard.stability = this.next_recall_stability(s.hard.difficulty, last_s, retrievability, models_1.Rating.Hard);
|
|
97
99
|
s.good.difficulty = this.next_difficulty(last_d, models_1.Rating.Good);
|
|
98
|
-
s.good.stability = this.next_recall_stability(s.good.difficulty, last_s, retrievability);
|
|
100
|
+
s.good.stability = this.next_recall_stability(s.good.difficulty, last_s, retrievability, models_1.Rating.Good);
|
|
99
101
|
s.easy.difficulty = this.next_difficulty(last_d, models_1.Rating.Easy);
|
|
100
|
-
s.easy.stability = this.next_recall_stability(s.easy.difficulty, last_s, retrievability);
|
|
102
|
+
s.easy.stability = this.next_recall_stability(s.easy.difficulty, last_s, retrievability, models_1.Rating.Easy);
|
|
101
103
|
}
|
|
102
104
|
/**
|
|
103
105
|
* The formula used is :
|
|
104
|
-
* $$S_0(G) =
|
|
106
|
+
* $$S_0(G) = w_{G-1}$$
|
|
105
107
|
* $$\max \{S_0,0.1\}$$
|
|
106
|
-
* @param g Grade (rating at Anki) [
|
|
108
|
+
* @param g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]
|
|
107
109
|
* @return Stability (interval when R=90%)
|
|
108
110
|
*/
|
|
109
111
|
init_stability(g) {
|
|
110
|
-
return Math.max(this.param.w[
|
|
112
|
+
return Math.max(this.param.w[g - 1], 0.1);
|
|
111
113
|
}
|
|
112
114
|
/**
|
|
113
115
|
* The formula used is :
|
|
114
|
-
* $$D_0(G) =
|
|
116
|
+
* $$D_0(G) = w_4 - (G-3) \cdot w_5$$
|
|
115
117
|
* $$\min \{\max \{D_0(G),1\},10\}$$
|
|
116
|
-
*
|
|
118
|
+
* where the D_0(3)=w_4 when the first rating is good.
|
|
119
|
+
* @param g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]
|
|
117
120
|
* @return Difficulty D \in [1,10]
|
|
118
121
|
*/
|
|
119
122
|
init_difficulty(g) {
|
|
120
|
-
return Math.min(Math.max(this.param.w[
|
|
123
|
+
return Math.min(Math.max(this.param.w[4] - (g - 3) * this.param.w[5], 1), 10);
|
|
121
124
|
}
|
|
122
125
|
apply_fuzz(ivl) {
|
|
123
126
|
if (!this.param.enable_fuzz || ivl < 2.5)
|
|
@@ -129,21 +132,26 @@ class FSRS {
|
|
|
129
132
|
const max_ivl = Math.round(ivl * 1.05 + 1);
|
|
130
133
|
return Math.floor(fuzz_factor * (max_ivl - min_ivl + 1) + min_ivl);
|
|
131
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Ref:
|
|
137
|
+
* constructor(param: Partial<FSRSParameters>)
|
|
138
|
+
* this.intervalModifier = 9 * (1 / this.param.request_retention - 1);
|
|
139
|
+
*/
|
|
132
140
|
next_interval(s) {
|
|
133
141
|
const newInterval = this.apply_fuzz(s * this.intervalModifier);
|
|
134
142
|
return Math.min(Math.max(Math.round(newInterval), 1), this.param.maximum_interval);
|
|
135
143
|
}
|
|
136
144
|
/**
|
|
137
145
|
* The formula used is :
|
|
138
|
-
* $$next_d = D
|
|
146
|
+
* $$next_d = D - w_6 \cdot (R - 2)$$
|
|
139
147
|
* $$D^\prime(D,R) = w_5 \cdot D_0(2) +(1 - w_5) \cdot next_d$$
|
|
140
148
|
* @param d
|
|
141
|
-
* @param g Grade (
|
|
149
|
+
* @param g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]
|
|
142
150
|
* @return next_D
|
|
143
151
|
*/
|
|
144
152
|
next_difficulty(d, g) {
|
|
145
|
-
const next_d = d
|
|
146
|
-
return this.constrain_difficulty(this.mean_reversion(this.param.w[
|
|
153
|
+
const next_d = d - this.param.w[6] * (g - 3);
|
|
154
|
+
return this.constrain_difficulty(this.mean_reversion(this.param.w[4], next_d));
|
|
147
155
|
}
|
|
148
156
|
/**
|
|
149
157
|
* The formula used is :
|
|
@@ -154,53 +162,58 @@ class FSRS {
|
|
|
154
162
|
}
|
|
155
163
|
/**
|
|
156
164
|
* The formula used is :
|
|
157
|
-
* $$
|
|
158
|
-
* @param init $$w_2 : D_0(
|
|
159
|
-
* @param current $$D
|
|
165
|
+
* $$w_7 \cdot init +(1 - w_7) \cdot current$$
|
|
166
|
+
* @param init $$w_2 : D_0(3) = w_2 + (R-2) \cdot w_3= w_2$$
|
|
167
|
+
* @param current $$D - w_6 \cdot (R - 2)$$
|
|
160
168
|
* @return difficulty
|
|
161
169
|
*/
|
|
162
170
|
mean_reversion(init, current) {
|
|
163
|
-
return this.param.w[
|
|
171
|
+
return this.param.w[7] * init + (1 - this.param.w[7]) * current;
|
|
164
172
|
}
|
|
165
173
|
/**
|
|
166
174
|
* The formula used is :
|
|
167
|
-
* $$S^\prime_r(D,S,R) = S\cdot(e^{
|
|
175
|
+
* $$S^\prime_r(D,S,R,G) = S\cdot(e^{w_8}\cdot (11-D)\cdot S^{-w_9}\cdot(e^{w_10\cdot(1-R)}-1)\cdot w_15(if G=2) \cdot w_16(if G=4)+1)$$
|
|
168
176
|
* @param d Difficulty D \in [1,10]
|
|
169
177
|
* @param s Stability (interval when R=90%)
|
|
170
178
|
* @param r Retrievability (probability of recall)
|
|
179
|
+
* @param g Grade (Rating[0.again,1.hard,2.good,3.easy])
|
|
171
180
|
* @return S^\prime_r new stability after recall
|
|
172
181
|
*/
|
|
173
|
-
next_recall_stability(d, s, r) {
|
|
182
|
+
next_recall_stability(d, s, r, g) {
|
|
183
|
+
const hard_penalty = models_1.Rating.Hard === g ? this.param.w[15] : 1;
|
|
184
|
+
const easy_bound = models_1.Rating.Easy === g ? this.param.w[16] : 1;
|
|
174
185
|
return (s *
|
|
175
186
|
(1 +
|
|
176
|
-
Math.exp(this.param.w[
|
|
187
|
+
Math.exp(this.param.w[8]) *
|
|
177
188
|
(11 - d) *
|
|
178
|
-
Math.pow(s, this.param.w[
|
|
179
|
-
(Math.exp((1 - r) * this.param.w[
|
|
189
|
+
Math.pow(s, -this.param.w[9]) *
|
|
190
|
+
(Math.exp((1 - r) * this.param.w[10]) - 1) *
|
|
191
|
+
hard_penalty *
|
|
192
|
+
easy_bound));
|
|
180
193
|
}
|
|
181
194
|
/**
|
|
182
195
|
* The formula used is :
|
|
183
|
-
* $$S^\prime_f(D,S,R) =
|
|
196
|
+
* $$S^\prime_f(D,S,R) = w_11\cdot D^{-w_{12}}\cdot ((S+1)^{w_{13}}-1) \cdot e^{w_{14}\cdot(1-R)}.$$
|
|
184
197
|
* @param d Difficulty D \in [1,10]
|
|
185
198
|
* @param s Stability (interval when R=90%)
|
|
186
199
|
* @param r Retrievability (probability of recall)
|
|
187
200
|
* @return S^\prime_f new stability after forgetting
|
|
188
201
|
*/
|
|
189
202
|
next_forget_stability(d, s, r) {
|
|
190
|
-
return (this.param.w[
|
|
191
|
-
Math.pow(d, this.param.w[
|
|
192
|
-
Math.pow(s, this.param.w[
|
|
193
|
-
Math.exp((1 - r) * this.param.w[
|
|
203
|
+
return (this.param.w[11] *
|
|
204
|
+
Math.pow(d, -this.param.w[12]) *
|
|
205
|
+
(Math.pow(s + 1, this.param.w[13]) - 1) *
|
|
206
|
+
Math.exp((1 - r) * this.param.w[14]));
|
|
194
207
|
}
|
|
195
208
|
/**
|
|
196
209
|
* The formula used is :
|
|
197
|
-
* $$R(t,S) =
|
|
210
|
+
* $$R(t,S) = (1 + \frac{t}{9 \cdot S})^{-1},$$
|
|
198
211
|
* @param t t days since the last review
|
|
199
212
|
* @param s Stability (interval when R=90%)
|
|
200
213
|
* @return r Retrievability (probability of recall)
|
|
201
214
|
*/
|
|
202
215
|
current_retrievability(t, s) {
|
|
203
|
-
return Math.
|
|
216
|
+
return Math.pow(1 + t / (9 * s), -1);
|
|
204
217
|
}
|
|
205
218
|
}
|
|
206
219
|
exports.FSRS = FSRS;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { SchedulingCard } from "./scheduler";
|
|
2
|
-
export { default_request_retention, default_maximum_interval,
|
|
2
|
+
export { default_request_retention, default_maximum_interval, default_w, default_enable_fuzz, FSRSVersion, generatorParameters, createEmptyCard, fsrs, envParams } from "./default";
|
|
3
3
|
export { date_scheduler, date_diff, formatDate, show_diff_message, } from "./help";
|
|
4
4
|
export type { int, double } from "./type";
|
|
5
5
|
export type { FSRSParameters, Card, ReviewLog, StateType, RatingType, } from "./models";
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FSRS = exports.Rating = exports.State = exports.show_diff_message = exports.formatDate = exports.date_diff = exports.date_scheduler = exports.envParams = exports.fsrs = exports.createEmptyCard = exports.generatorParameters = exports.FSRSVersion = exports.default_enable_fuzz = exports.default_w = exports.
|
|
3
|
+
exports.FSRS = exports.Rating = exports.State = exports.show_diff_message = exports.formatDate = exports.date_diff = exports.date_scheduler = exports.envParams = exports.fsrs = exports.createEmptyCard = exports.generatorParameters = exports.FSRSVersion = exports.default_enable_fuzz = exports.default_w = exports.default_maximum_interval = exports.default_request_retention = exports.SchedulingCard = void 0;
|
|
4
4
|
var scheduler_1 = require("./scheduler");
|
|
5
5
|
Object.defineProperty(exports, "SchedulingCard", { enumerable: true, get: function () { return scheduler_1.SchedulingCard; } });
|
|
6
6
|
var default_1 = require("./default");
|
|
7
7
|
Object.defineProperty(exports, "default_request_retention", { enumerable: true, get: function () { return default_1.default_request_retention; } });
|
|
8
8
|
Object.defineProperty(exports, "default_maximum_interval", { enumerable: true, get: function () { return default_1.default_maximum_interval; } });
|
|
9
|
-
Object.defineProperty(exports, "default_easy_bonus", { enumerable: true, get: function () { return default_1.default_easy_bonus; } });
|
|
10
|
-
Object.defineProperty(exports, "default_hard_factor", { enumerable: true, get: function () { return default_1.default_hard_factor; } });
|
|
11
9
|
Object.defineProperty(exports, "default_w", { enumerable: true, get: function () { return default_1.default_w; } });
|
|
12
10
|
Object.defineProperty(exports, "default_enable_fuzz", { enumerable: true, get: function () { return default_1.default_enable_fuzz; } });
|
|
13
11
|
Object.defineProperty(exports, "FSRSVersion", { enumerable: true, get: function () { return default_1.FSRSVersion; } });
|
package/dist/models.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type StateType = "
|
|
1
|
+
export type StateType = "New" | "Learning" | "Review" | "Relearning";
|
|
2
2
|
export declare enum State {
|
|
3
3
|
New = 0,
|
|
4
4
|
Learning = 1,
|
|
@@ -7,10 +7,10 @@ export declare enum State {
|
|
|
7
7
|
}
|
|
8
8
|
export type RatingType = "Again" | "Hard" | "Good" | "Easy";
|
|
9
9
|
export declare enum Rating {
|
|
10
|
-
Again =
|
|
11
|
-
Hard =
|
|
12
|
-
Good =
|
|
13
|
-
Easy =
|
|
10
|
+
Again = 1,
|
|
11
|
+
Hard = 2,
|
|
12
|
+
Good = 3,
|
|
13
|
+
Easy = 4
|
|
14
14
|
}
|
|
15
15
|
export interface ReviewLog {
|
|
16
16
|
rating: Rating;
|
|
@@ -33,8 +33,6 @@ export interface Card {
|
|
|
33
33
|
export interface FSRSParameters {
|
|
34
34
|
request_retention: number;
|
|
35
35
|
maximum_interval: number;
|
|
36
|
-
easy_bonus: number;
|
|
37
|
-
hard_factor: number;
|
|
38
36
|
w: number[];
|
|
39
37
|
enable_fuzz: boolean;
|
|
40
38
|
}
|
package/dist/models.js
CHANGED
|
@@ -10,8 +10,8 @@ var State;
|
|
|
10
10
|
})(State || (exports.State = State = {}));
|
|
11
11
|
var Rating;
|
|
12
12
|
(function (Rating) {
|
|
13
|
-
Rating[Rating["Again"] =
|
|
14
|
-
Rating[Rating["Hard"] =
|
|
15
|
-
Rating[Rating["Good"] =
|
|
16
|
-
Rating[Rating["Easy"] =
|
|
13
|
+
Rating[Rating["Again"] = 1] = "Again";
|
|
14
|
+
Rating[Rating["Hard"] = 2] = "Hard";
|
|
15
|
+
Rating[Rating["Good"] = 3] = "Good";
|
|
16
|
+
Rating[Rating["Easy"] = 4] = "Easy";
|
|
17
17
|
})(Rating || (exports.Rating = Rating = {}));
|
package/dist/scheduler.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare class SchedulingCard {
|
|
|
9
9
|
update_state(state: State): this;
|
|
10
10
|
schedule(now: Date, hard_interval: number, good_interval: number, easy_interval: number): SchedulingCard;
|
|
11
11
|
record_log(card: Card, now: Date): {
|
|
12
|
-
|
|
12
|
+
1: {
|
|
13
13
|
card: Card;
|
|
14
14
|
log: {
|
|
15
15
|
rating: Rating;
|
|
@@ -19,7 +19,7 @@ export declare class SchedulingCard {
|
|
|
19
19
|
review: Date;
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
|
-
|
|
22
|
+
2: {
|
|
23
23
|
card: Card;
|
|
24
24
|
log: {
|
|
25
25
|
rating: Rating;
|
|
@@ -29,7 +29,7 @@ export declare class SchedulingCard {
|
|
|
29
29
|
review: Date;
|
|
30
30
|
};
|
|
31
31
|
};
|
|
32
|
-
|
|
32
|
+
3: {
|
|
33
33
|
card: Card;
|
|
34
34
|
log: {
|
|
35
35
|
rating: Rating;
|
|
@@ -39,7 +39,7 @@ export declare class SchedulingCard {
|
|
|
39
39
|
review: Date;
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
|
-
|
|
42
|
+
4: {
|
|
43
43
|
card: Card;
|
|
44
44
|
log: {
|
|
45
45
|
rating: Rating;
|
package/dist/type.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-fsrs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "ts-fsrs is a TypeScript package used to implement the Free Spaced Repetition Scheduler (FSRS) algorithm. It helps developers apply FSRS to their flashcard applications, thereby improving the user learning experience.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|