From 20a5d4896a5f1fd972cef046e83a890df8fcf74c Mon Sep 17 00:00:00 2001 From: ishiko Date: Mon, 16 Dec 2024 21:26:12 +0800 Subject: [PATCH 1/5] Fix/clip post-lapse stability --- src/fsrs/algorithm.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fsrs/algorithm.ts b/src/fsrs/algorithm.ts index 3a24f1a..2dc9cb1 100644 --- a/src/fsrs/algorithm.ts +++ b/src/fsrs/algorithm.ts @@ -233,19 +233,22 @@ export class FSRSAlgorithm { /** * The formula used is : * $$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)}$$ + * $$S^\prime_f = \min \lbrace \max \lbrace S^\prime_f,0.01\rbrace, \frac{S}{e^{w_{17} \cdot w_{18}}} \rbrace$$ * @param {number} d Difficulty D \in [1,10] * @param {number} s Stability (interval when R=90%) * @param {number} r Retrievability (probability of recall) * @return {number} S^\prime_f new stability after forgetting */ next_forget_stability(d: number, s: number, r: number): number { + const new_s_max = s / Math.exp(this.param.w[17] * this.param.w[18]) + return +clamp( this.param.w[11] * Math.pow(d, -this.param.w[12]) * (Math.pow(s + 1, this.param.w[13]) - 1) * Math.exp((1 - r) * this.param.w[14]), 0.01, - 36500.0 + new_s_max ).toFixed(8) } From f855a021df467d8b0c5f64f7ac3b35e2d6993d25 Mon Sep 17 00:00:00 2001 From: ishiko Date: Tue, 17 Dec 2024 10:38:11 +0800 Subject: [PATCH 2/5] consider enable_short_term --- src/fsrs/algorithm.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/fsrs/algorithm.ts b/src/fsrs/algorithm.ts index 2dc9cb1..1c24b08 100644 --- a/src/fsrs/algorithm.ts +++ b/src/fsrs/algorithm.ts @@ -233,14 +233,18 @@ export class FSRSAlgorithm { /** * The formula used is : * $$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)}$$ - * $$S^\prime_f = \min \lbrace \max \lbrace S^\prime_f,0.01\rbrace, \frac{S}{e^{w_{17} \cdot w_{18}}} \rbrace$$ + * enable_short_term = true : $$S^\prime_f \in \min \lbrace \max \lbrace S^\prime_f,0.01\rbrace, \frac{S}{e^{w_{17} \cdot w_{18}}} \rbrace$$ + * enable_short_term = false : $$S^\prime_f \in \min \lbrace \max \lbrace S^\prime_f,0.01\rbrace, S \rbrace$$ * @param {number} d Difficulty D \in [1,10] * @param {number} s Stability (interval when R=90%) * @param {number} r Retrievability (probability of recall) * @return {number} S^\prime_f new stability after forgetting */ next_forget_stability(d: number, s: number, r: number): number { - const new_s_max = s / Math.exp(this.param.w[17] * this.param.w[18]) + let new_s_max = s + if (this.param.enable_short_term) { + new_s_max = s / Math.exp(this.param.w[17] * this.param.w[18]) + } return +clamp( this.param.w[11] * From dba933fd9cb8a9f0106b10d53fbe860d2de02373 Mon Sep 17 00:00:00 2001 From: ishiko Date: Tue, 17 Dec 2024 10:44:44 +0800 Subject: [PATCH 3/5] modify the impl method --- src/fsrs/algorithm.ts | 7 +------ src/fsrs/impl/basic_scheduler.ts | 7 +++++++ src/fsrs/impl/long_term_scheduler.ts | 2 ++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/fsrs/algorithm.ts b/src/fsrs/algorithm.ts index 1c24b08..73aedae 100644 --- a/src/fsrs/algorithm.ts +++ b/src/fsrs/algorithm.ts @@ -241,18 +241,13 @@ export class FSRSAlgorithm { * @return {number} S^\prime_f new stability after forgetting */ next_forget_stability(d: number, s: number, r: number): number { - let new_s_max = s - if (this.param.enable_short_term) { - new_s_max = s / Math.exp(this.param.w[17] * this.param.w[18]) - } - return +clamp( this.param.w[11] * Math.pow(d, -this.param.w[12]) * (Math.pow(s + 1, this.param.w[13]) - 1) * Math.exp((1 - r) * this.param.w[14]), 0.01, - new_s_max + 36500.0 ).toFixed(8) } diff --git a/src/fsrs/impl/basic_scheduler.ts b/src/fsrs/impl/basic_scheduler.ts index e3583c6..7be9bf5 100644 --- a/src/fsrs/impl/basic_scheduler.ts +++ b/src/fsrs/impl/basic_scheduler.ts @@ -191,6 +191,13 @@ export default class BasicScheduler extends AbstractScheduler { stability, retrievability ) + const nextSMin = + stability / + Math.exp( + this.algorithm.parameters.w[17] * this.algorithm.parameters.w[18] + ) + next_again.stability = Math.min(nextSMin, next_again.stability) + next_hard.difficulty = this.algorithm.next_difficulty( difficulty, Rating.Hard diff --git a/src/fsrs/impl/long_term_scheduler.ts b/src/fsrs/impl/long_term_scheduler.ts index 95703ee..8a30bfd 100644 --- a/src/fsrs/impl/long_term_scheduler.ts +++ b/src/fsrs/impl/long_term_scheduler.ts @@ -117,6 +117,8 @@ export default class LongTermScheduler extends AbstractScheduler { stability, retrievability ) + next_again.stability = Math.min(stability, next_again.stability) + next_hard.difficulty = this.algorithm.next_difficulty( difficulty, Rating.Hard From a7a9ad53bdc0de91ef994d4e8a7f61a99959dc47 Mon Sep 17 00:00:00 2001 From: ishiko Date: Tue, 17 Dec 2024 10:45:56 +0800 Subject: [PATCH 4/5] bump version to 4.5.1 --- package.json | 2 +- src/fsrs/default.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e0f9aaa..a0a81c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts-fsrs", - "version": "4.5.0", + "version": "4.5.1", "description": "ts-fsrs is a versatile package based on TypeScript that supports ES modules, CommonJS, and UMD. It implements the Free Spaced Repetition Scheduler (FSRS) algorithm, enabling developers to integrate FSRS into their flashcard applications to enhance the user learning experience.", "main": "dist/index.cjs", "umd": "dist/index.umd.js", diff --git a/src/fsrs/default.ts b/src/fsrs/default.ts index 82c38d1..6902b2f 100644 --- a/src/fsrs/default.ts +++ b/src/fsrs/default.ts @@ -11,7 +11,7 @@ export const default_w = [ export const default_enable_fuzz = false export const default_enable_short_term = true -export const FSRSVersion: string = 'v4.5.0 using FSRS-5.0' +export const FSRSVersion: string = 'v4.5.1 using FSRS-5.0' export const generatorParameters = ( props?: Partial From ecbe9e446b214a3b9c0373dff7083aca09ffca49 Mon Sep 17 00:00:00 2001 From: ishiko Date: Tue, 17 Dec 2024 19:33:57 +0800 Subject: [PATCH 5/5] pref code --- src/fsrs/impl/basic_scheduler.ts | 14 ++++++++------ src/fsrs/impl/long_term_scheduler.ts | 12 +++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/fsrs/impl/basic_scheduler.ts b/src/fsrs/impl/basic_scheduler.ts index 7be9bf5..b0574c0 100644 --- a/src/fsrs/impl/basic_scheduler.ts +++ b/src/fsrs/impl/basic_scheduler.ts @@ -186,17 +186,19 @@ export default class BasicScheduler extends AbstractScheduler { difficulty, Rating.Again ) - next_again.stability = this.algorithm.next_forget_stability( - difficulty, - stability, - retrievability - ) const nextSMin = stability / Math.exp( this.algorithm.parameters.w[17] * this.algorithm.parameters.w[18] ) - next_again.stability = Math.min(nextSMin, next_again.stability) + next_again.stability = Math.min( + +nextSMin.toFixed(8), + this.algorithm.next_forget_stability( + difficulty, + stability, + retrievability + ) + ) next_hard.difficulty = this.algorithm.next_difficulty( difficulty, diff --git a/src/fsrs/impl/long_term_scheduler.ts b/src/fsrs/impl/long_term_scheduler.ts index 8a30bfd..5616a9a 100644 --- a/src/fsrs/impl/long_term_scheduler.ts +++ b/src/fsrs/impl/long_term_scheduler.ts @@ -112,13 +112,15 @@ export default class LongTermScheduler extends AbstractScheduler { difficulty, Rating.Again ) - next_again.stability = this.algorithm.next_forget_stability( - difficulty, + next_again.stability = Math.min( stability, - retrievability + this.algorithm.next_forget_stability( + difficulty, + stability, + retrievability + ) ) - next_again.stability = Math.min(stability, next_again.stability) - + next_hard.difficulty = this.algorithm.next_difficulty( difficulty, Rating.Hard