Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/allow parameters to be modified #81

Merged
merged 3 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions __tests__/algorithm.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {
DECAY,
default_enable_fuzz,
default_maximum_interval,
default_request_retention,
default_w,
FACTOR,
fsrs,
FSRS,
Expand Down Expand Up @@ -296,3 +299,60 @@ describe("FSRS apply_fuzz", () => {
expect(fuzzedInterval).toBeLessThanOrEqual(max_ivl);
});
});

describe("change Params", () => {
test("change FSRSParameters", () => {
const f = fsrs();
// I(r,s),r=0.9 then I(r,s)=s
expect(f.interval_modifier).toEqual(1);
expect(f.parameters).toEqual(generatorParameters());

const request_retention = 0.8;
const update_w = [
1.14, 1.01, 5.44, 14.67, 5.3024, 1.5662, 1.2503, 0.0028, 1.5489, 0.1763,
0.9953, 2.7473, 0.0179, 0.3105, 0.3976, 0.0, 2.0902,
];
f.parameters = generatorParameters({
request_retention: request_retention,
w: update_w,
enable_fuzz: true,
});
expect(f.parameters.request_retention).toEqual(request_retention);
expect(f.parameters.w).toEqual(update_w);
expect(f.parameters.enable_fuzz).toEqual(true);
expect(f.interval_modifier).toEqual(
f.calculate_interval_modifier(request_retention),
);

f.parameters.request_retention = default_request_retention;
expect(f.interval_modifier).toEqual(
f.calculate_interval_modifier(default_request_retention),
);

f.parameters.w = default_w;
expect(f.parameters.w).toEqual(default_w);

f.parameters.maximum_interval = 365;
expect(f.parameters.maximum_interval).toEqual(365);

f.parameters.enable_fuzz = default_enable_fuzz;
expect(f.parameters.enable_fuzz).toEqual(default_enable_fuzz);

f.parameters = {} // check default values
expect(f.parameters).toEqual(generatorParameters());

});

test("calculate_interval_modifier", () => {
const f = new FSRSAlgorithm(generatorParameters());
expect(f.interval_modifier).toEqual(
f.calculate_interval_modifier(default_request_retention),
);
expect(() => {
f.parameters.request_retention = 1.2;
}).toThrow("Requested retention rate should be in the range (0,1]");
expect(() => {
f.parameters.request_retention = -0.2;
}).toThrow("Requested retention rate should be in the range (0,1]");
});
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ts-fsrs",
"version": "3.5.3",
"version": "3.5.4",
"description": "ts-fsrs is a ES modules package based on TypeScript, used to implement the Free Spaced Repetition Scheduler (FSRS) algorithm. It helps developers apply FSRS to their flashcard applications, there by improving the user learning experience.",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
Expand Down
69 changes: 61 additions & 8 deletions src/fsrs/algorithm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,69 @@ export const DECAY: number = -0.5;
export const FACTOR: number = 19 / 81;

export class FSRSAlgorithm {
protected param: FSRSParameters;
private readonly intervalModifier: number;
protected param!: FSRSParameters;
protected intervalModifier!: number;
protected seed?: string;

constructor(param: Partial<FSRSParameters>) {
this.param = generatorParameters(param);
// Ref: https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-45
// The formula used is : I(r,s)= (r^{\frac{1}{DECAY}-1}) \times \frac{s}{FACTOR}
this.intervalModifier =
(Math.pow(this.param.request_retention, 1 / DECAY) - 1) / FACTOR;
constructor(params: Partial<FSRSParameters>) {
this.param = new Proxy(
generatorParameters(params),
this.params_handler_proxy(),
);
this.intervalModifier = this.calculate_interval_modifier(
this.param.request_retention,
);
}

get interval_modifier(): number {
return this.intervalModifier;
}

/**
* Ref: https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-45
* The formula used is: I(r,s) = (r^(1/DECAY) - 1) * s / FACTOR
* @param request_retention 0<request_retention<=1,Requested retention rate
*/
calculate_interval_modifier(request_retention: number): number {
if (request_retention <= 0 || request_retention > 1) {
throw new Error("Requested retention rate should be in the range (0,1]");
}
return +((Math.pow(request_retention, 1 / DECAY) - 1) / FACTOR).toFixed(8);
}

get parameters(): FSRSParameters {
return this.param;
}

set parameters(params: Partial<FSRSParameters>) {
this.update_parameters(params);
}

private params_handler_proxy(): ProxyHandler<FSRSParameters> {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const _this: FSRSAlgorithm = this;
return {
set: function (target, prop, value) {
if (prop === "request_retention" && Number.isFinite(value)) {
_this.intervalModifier = _this.calculate_interval_modifier(
Number(value),
);
}
// @ts-ignore
target[prop] = value;
return true;
},
};
}

private update_parameters(params: Partial<FSRSParameters>): void {
const _params = generatorParameters(params);
for (const key in _params) {
if (key in this.param) {
const paramKey = key as keyof FSRSParameters;
this.param[paramKey] = _params[paramKey] as never;
}
}
}

init_ds(s: SchedulingCard): void {
Expand Down
2 changes: 1 addition & 1 deletion src/fsrs/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const default_w = [
];
export const default_enable_fuzz = false;

export const FSRSVersion: string = "3.5.3";
export const FSRSVersion: string = "3.5.4";

export const generatorParameters = (
props?: Partial<FSRSParameters>,
Expand Down
Loading