From 092c5d7f1f0501cc88c4d6c777f4ee5680bbbf00 Mon Sep 17 00:00:00 2001 From: ishiko Date: Wed, 18 Sep 2024 23:26:42 +0800 Subject: [PATCH] Fix/`Stability` is not restricted to maximum or minimum values. --- __tests__/FSRSV5.test.ts | 2 +- src/fsrs/algorithm.ts | 36 +++++++++++++++++++++--------------- src/fsrs/help.ts | 4 ++++ 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/__tests__/FSRSV5.test.ts b/__tests__/FSRSV5.test.ts index b7380d98..9ba851ac 100644 --- a/__tests__/FSRSV5.test.ts +++ b/__tests__/FSRSV5.test.ts @@ -166,7 +166,7 @@ describe('get retrievability', () => { let card = createEmptyCard() let now = new Date() let i = 0 - while (i < 10 ** 3) { + while (i < 5) { card = fsrs.next(card, now, Rating.Again).card now = card.due i++ diff --git a/src/fsrs/algorithm.ts b/src/fsrs/algorithm.ts index f1a772e2..131fc02b 100644 --- a/src/fsrs/algorithm.ts +++ b/src/fsrs/algorithm.ts @@ -1,7 +1,7 @@ import { generatorParameters } from './default' import { FSRSParameters, Grade, Rating } from './models' import type { int } from './types' -import { get_fuzz_range } from './help' +import { clamp, get_fuzz_range } from './help' import { alea } from './alea' /** @@ -213,15 +213,17 @@ export class FSRSAlgorithm { next_recall_stability(d: number, s: number, r: number, g: Grade): number { const hard_penalty = Rating.Hard === g ? this.param.w[15] : 1 const easy_bound = Rating.Easy === g ? this.param.w[16] : 1 - return +( + return +clamp( s * - (1 + - Math.exp(this.param.w[8]) * - (11 - d) * - Math.pow(s, -this.param.w[9]) * - (Math.exp((1 - r) * this.param.w[10]) - 1) * - hard_penalty * - easy_bound) + (1 + + Math.exp(this.param.w[8]) * + (11 - d) * + Math.pow(s, -this.param.w[9]) * + (Math.exp((1 - r) * this.param.w[10]) - 1) * + hard_penalty * + easy_bound), + 0.01, + this.param.maximum_interval ).toFixed(8) } @@ -234,11 +236,13 @@ export class FSRSAlgorithm { * @return {number} S^\prime_f new stability after forgetting */ next_forget_stability(d: number, s: number, r: number): number { - return +( + 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]) + 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, + this.param.maximum_interval ).toFixed(8) } @@ -249,8 +253,10 @@ export class FSRSAlgorithm { * @param {Grade} g Grade (Rating[0.again,1.hard,2.good,3.easy]) */ next_short_term_stability(s: number, g: Grade): number { - return +( - s * Math.exp(this.param.w[17] * (g - 3 + this.param.w[18])) + return +clamp( + s * Math.exp(this.param.w[17] * (g - 3 + this.param.w[18])), + 0.01, + this.param.maximum_interval ).toFixed(8) } diff --git a/src/fsrs/help.ts b/src/fsrs/help.ts index 1a2839b8..8d63eda4 100644 --- a/src/fsrs/help.ts +++ b/src/fsrs/help.ts @@ -187,3 +187,7 @@ export function get_fuzz_range( min_ivl = Math.min(min_ivl, max_ivl) return { min_ivl, max_ivl } } + +export function clamp(value: number, min: number, max: number): number { + return Math.min(Math.max(value, min), max) +}