For AI agents: the complete documentation index is available at https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/llms.txt, the full documentation bundle is available at https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/llms-full.txt, and this page is available as Markdown at https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/index.md.

モデル概要

FSRS モデルは、評価と経過時間から新しい記憶状態を求め、忘却曲線で想起確率を推定し、記憶状態と目標保持率から基本間隔を計算します。

このセクションの FSRS-3 から FSRS-6 の用語と数式は awesome-fsrs Wiki、特に The Algorithm を基準に確認しています。TypeScript API とフレームワークの責務境界は ts-fsrs 自体に基づきます。

モデルの境界

モデルが担うのは、記憶状態の更新、忘却曲線の計算、基本間隔の計算です。scheduler は復習処理を統括し、chrono は日時と経過時間を扱い、middleware は学習ステップ、ファジング、最大間隔、キュー状態のポリシーを適用します。

For your Agent
SRS モデルを実装または説明する

このプロンプトをコピーすると、AI Agent がスケジューリングポリシーを混在させずに Model 契約へ従います。

共通の記号

記号意味
DD難易度。1(最も簡単)から 10(最も難しい)までです。
SSFSRS-3〜6 の安定度(日数)。t=St = S のとき想起確率は 90% です。
RRtt 日後に思い出せる確率の推定値です。
GG評価。1 は Again、2 は Hard、3 は Good、4 は Easy です。
tt前回の復習からの経過日数です。
rrnextInterval が使う目標保持率です。
I(r,S)I(r, S)安定度 SS と目標保持率 rr から求める基本間隔(日数)。middleware のポリシーを適用する前の値です。
Smin⁡S_{\min}、Smax⁡S_{\max}モデルが許容する安定度の下限と上限です。
Dmin⁡D_{\min}、Dmax⁡D_{\max}モデルが許容する難易度の下限と上限です。
wiw_i学習済みのモデル重みです。

FSRS-7 は実装のスナップショットを基に別途説明します。速い安定度を追加し、混合曲線を使って小数の日数の間隔を返します。上表の安定度の 90% 定義と I(r, S) の記法は FSRS-3〜6 に適用されます。

バージョン別モデルを使う

DefaultScheduler は既定で FSRS-7 を使い、version オプションで対応する FSRS バージョンを選択できます。各バージョンのモデルを直接作成して呼び出すこともできます。以下の例では FSRS-6 を使います。

import { 
type Rating = 0 | 1 | 2 | 3 | 4
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
} from 'ts-fsrs'
import {
const FSRS6_DEFAULT_WEIGHTS: number[]
FSRS6_DEFAULT_WEIGHTS
,
const FSRS6Model: Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>
FSRS6Model
} from 'ts-fsrs/models/fsrs-6'
const
const model: ModelCore<{
    readonly config: {
        readonly weights: number[];
        readonly enableShortTerm: boolean;
        readonly numRelearningSteps: number;
    };
    readonly memoryState: {
        stability: number;
        difficulty: number;
    };
    readonly algorithm: FSRS6Algorithm;
}>
model
=
const FSRS6Model: Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>
FSRS6Model
.
Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>.create: (ctx: {
    readonly config: {
        readonly weights: number[];
        readonly enableShortTerm: boolean;
        readonly numRelearningSteps: number;
    } | {
        readonly weights: number[];
        readonly enableShortTerm: boolean;
        readonly numRelearningSteps: number;
    };
    readonly migrate?: boolean;
    readonly clip?: boolean;
    readonly check?: boolean;
    readonly bypass?: boolean;
}) => ModelCore<{
    readonly config: {
        readonly weights: number[];
        readonly enableShortTerm: boolean;
        readonly numRelearningSteps: number;
    };
    readonly memoryState: {
        stability: number;
        difficulty: number;
    };
    readonly algorithm: FSRS6Algorithm;
}>
create
({
config: { weights:
const FSRS6_DEFAULT_WEIGHTS: number[]
FSRS6_DEFAULT_WEIGHTS
,
enableShortTerm: true, numRelearningSteps: 1, // Constrains weights; middleware runs the steps. }, }) const memoryState =
const model: ModelCore<{
    readonly config: {
        readonly weights: number[];
        readonly enableShortTerm: boolean;
        readonly numRelearningSteps: number;
    };
    readonly memoryState: {
        stability: number;
        difficulty: number;
    };
    readonly algorithm: FSRS6Algorithm;
}>
model
.
ModelCore<{ readonly config: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; readonly memoryState: { stability: number; difficulty: number; }; readonly algorithm: FSRS6Algorithm; }>.step: (input: ModelStepInput<{
    stability: number;
    difficulty: number;
}>) => {
    stability: number;
    difficulty: number;
}
step
({
ModelStepInput<{ stability: number; difficulty: number; }>.memoryState: Readonly<{
    stability: number;
    difficulty: number;
}> | null
memoryState
: null,
ModelStepInput<{ stability: number; difficulty: number; }>.rating: 1 | 2 | 3 | 4
rating
:
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Good,
ModelStepInput<{ stability: number; difficulty: number; }>.elapsedDays: number
elapsedDays
: 0,
}) const desiredRetention = 0.9 const interval =
const model: ModelCore<{
    readonly config: {
        readonly weights: number[];
        readonly enableShortTerm: boolean;
        readonly numRelearningSteps: number;
    };
    readonly memoryState: {
        stability: number;
        difficulty: number;
    };
    readonly algorithm: FSRS6Algorithm;
}>
model
.
ModelCore<{ readonly config: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; readonly memoryState: { stability: number; difficulty: number; }; readonly algorithm: FSRS6Algorithm; }>.nextInterval: (memoryState: Readonly<{
    stability: number;
    difficulty: number;
}>, desiredRetention: number) => number
nextInterval
(memoryState, desiredRetention)
const retrievabilityAtInterval =
const model: ModelCore<{
    readonly config: {
        readonly weights: number[];
        readonly enableShortTerm: boolean;
        readonly numRelearningSteps: number;
    };
    readonly memoryState: {
        stability: number;
        difficulty: number;
    };
    readonly algorithm: FSRS6Algorithm;
}>
model
.
ModelCore<{ readonly config: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; readonly memoryState: { stability: number; difficulty: number; }; readonly algorithm: FSRS6Algorithm; }>.forgettingCurve: (memoryState: Readonly<{
    stability: number;
    difficulty: number;
}>, elapsedDays: number) => number
forgettingCurve
(memoryState, interval)
console.log( JSON.stringify( { memoryState, desiredRetention, interval, retrievabilityAtInterval, }, null, 2 ) )

この例では、まず目標保持率 90% に対応する復習間隔を計算し、次に forgettingCurve でその間隔における想起確率を推定します。FSRS-6 の nextInterval は整数の日数を返すため、結果は 90% とわずかに異なる場合があります。

FSRS-6 の設定では、enableShortTerm がモデルの同日安定度更新を制御します。numRelearningSteps は重みのクリッピングと検査にだけ使われ、再学習ステップのスケジューリングは引き続き middleware が担います。

モデルを定義する

defineModel は具体的な設定、記憶状態、アルゴリズムの型を保ち、schema、既定値、モデルコアのファクトリーを一つの定義にまとめます。defineModel 自体は設定を解析しません。

以下では SM-2 の派生版 を実装し、モデルの定義方法を示します。

import {
  
function clamp(value: number, min: number, max: number): number
clamp
,
function defineModel<const Name extends string | symbol, const ConfigSchema extends AnySchema, const MemoryStateSchema extends AnyObjectSchema, const Algorithm>(definition: {
    readonly name: Name;
    readonly schema: ModelSchema<{
        readonly config: ConfigSchema;
        readonly memoryState: MemoryStateSchema;
    }>;
    readonly defaultValue: {
        readonly memoryState: (ctx: {
            readonly config: SchemaOutput<ConfigSchema>;
        }) => SchemaInput<MemoryStateSchema>;
    };
    readonly create: ModelCreate<{
        readonly config: ConfigSchema;
        readonly memoryState: MemoryStateSchema;
    }, Algorithm>;
}): Model<{
    readonly name: Name;
    readonly config: ConfigSchema;
    readonly memoryState: MemoryStateSchema;
    readonly algorithm: Algorithm;
}>
defineModel
,
type
interface ModelForwardInput<MemoryState extends object>
ModelForwardInput
,
type
interface ModelStepInput<MemoryState extends object>
ModelStepInput
,
type Rating = 0 | 1 | 2 | 3 | 4
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
,
} from 'ts-fsrs' import { z } from 'zod' const configSchema = z.object({ weights: z.tuple([ z.number().min(0.01).max(100), z.number().min(0.01).max(100), z.number().min(1.3).max(10), z.number().nonnegative(), z.number().min(5), z.number(), ]), }) const memoryStateSchema = z.object({ interval: z.number().min(0).max(36500), easeFactor: z.number().min(1.3).max(10), repetitions: z.number().int().nonnegative(), }) type
type MemoryState = {
    interval: number;
    easeFactor: number;
    repetitions: number;
}
MemoryState
= z.output<typeof memoryStateSchema>
const
const SM2Model: Model<{
    readonly name: "sm2";
    readonly config: z.ZodObject<{
        weights: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
    }, z.core.$strip>;
    readonly memoryState: z.ZodObject<{
        interval: z.ZodNumber;
        easeFactor: z.ZodNumber;
        repetitions: z.ZodNumber;
    }, z.core.$strip>;
    readonly algorithm: null;
}>
SM2Model
=
defineModel<"sm2", z.ZodObject<{
    weights: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
}, z.core.$strip>, z.ZodObject<{
    interval: z.ZodNumber;
    easeFactor: z.ZodNumber;
    repetitions: z.ZodNumber;
}, z.core.$strip>, null>(definition: {
    readonly name: "sm2";
    readonly schema: ModelSchema<{
        readonly config: z.ZodObject<{
            weights: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
        }, z.core.$strip>;
        readonly memoryState: z.ZodObject<{
            ...;
        }, z.core.$strip>;
    }>;
    readonly defaultValue: {
        ...;
    };
    readonly create: ModelCreate<...>;
}): Model<...>
defineModel
({
name: 'sm2',
schema: ModelSchema<{
    readonly config: z.ZodObject<{
        weights: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
    }, z.core.$strip>;
    readonly memoryState: z.ZodObject<{
        interval: z.ZodNumber;
        easeFactor: z.ZodNumber;
        repetitions: z.ZodNumber;
    }, z.core.$strip>;
}>
schema
: {
ModelSchema<{ readonly config: ZodObject<{ weights: ZodTuple<[ZodNumber, ZodNumber, ZodNumber, ZodNumber, ZodNumber, ZodNumber], null>; }, $strip>; readonly memoryState: ZodObject<...>; }>.config: z.ZodObject<{
    weights: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
}, z.core.$strip>
config
: configSchema,
ModelSchema<{ readonly config: ZodObject<{ weights: ZodTuple<[ZodNumber, ZodNumber, ZodNumber, ZodNumber, ZodNumber, ZodNumber], null>; }, $strip>; readonly memoryState: ZodObject<...>; }>.memoryState: z.ZodObject<{
    interval: z.ZodNumber;
    easeFactor: z.ZodNumber;
    repetitions: z.ZodNumber;
}, z.core.$strip>
memoryState
: memoryStateSchema },
defaultValue: { memoryState: ({ config }) => ({ interval: 0, easeFactor: config.weights[2], repetitions: 0, }), },
create: ModelCreate<{
    readonly config: z.ZodObject<{
        weights: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
    }, z.core.$strip>;
    readonly memoryState: z.ZodObject<{
        interval: z.ZodNumber;
        easeFactor: z.ZodNumber;
        repetitions: z.ZodNumber;
    }, z.core.$strip>;
}, null>
create
({ config }) {
const parsed = configSchema.
ZodType<any, any, $ZodObjectInternals<{ weights: ZodTuple<[ZodNumber, ZodNumber, ZodNumber, ZodNumber, ZodNumber, ZodNumber], null>; }, $strip>>.parse(data: unknown, params?: z.core.ParseContext<z.core.$ZodIssue>): {
    weights: [number, number, number, number, number, number];
}
parse
(config)
const w = parsed.weights const
const step: ({ memoryState, rating }: ModelStepInput<MemoryState>) => {
    interval: number;
    easeFactor: number;
    repetitions: number;
}
step
= ({ memoryState, rating }:
interface ModelStepInput<MemoryState extends object>
ModelStepInput
<
type MemoryState = {
    interval: number;
    easeFactor: number;
    repetitions: number;
}
MemoryState
>) => {
const previous = memoryState ?? { interval: 0, easeFactor: parsed.weights[2], repetitions: 0, } // Again / Hard / Good / Easy -> SM-2 quality 2 / 3 / 4 / 5. const quality = rating + 1 const repetitions = rating >
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Again ? previous.repetitions + 1 : 0
const interval =
function clamp(value: number, min: number, max: number): number
clamp
(
repetitions <= 1 ? w[0] : repetitions === 2 ? w[1] : previous.interval * previous.easeFactor, 0.01, 36500 ) const easeFactor =
function clamp(value: number, min: number, max: number): number
clamp
(
previous.easeFactor - w[3] * (quality - w[4]) ** 2 + w[5], 1.3, 10 ) return { interval, easeFactor, repetitions } } const
const forward: ({ history, initialState, }: ModelForwardInput<MemoryState>) => {
    interval: number;
    easeFactor: number;
    repetitions: number;
}[]
forward
= ({
history: readonly ModelReview[]
history
,
initialState, }:
interface ModelForwardInput<MemoryState extends object>
ModelForwardInput
<
type MemoryState = {
    interval: number;
    easeFactor: number;
    repetitions: number;
}
MemoryState
>) => {
const
const states: {
    interval: number;
    easeFactor: number;
    repetitions: number;
}[]
states
:
type MemoryState = {
    interval: number;
    easeFactor: number;
    repetitions: number;
}
MemoryState
[] = []
let memoryState = initialState ?? null for (const
const review: ModelReview
review
of
history: readonly ModelReview[]
history
) {
memoryState =
const step: ({ memoryState, rating }: ModelStepInput<MemoryState>) => {
    interval: number;
    easeFactor: number;
    repetitions: number;
}
step
({
ModelStepInput<{ interval: number; easeFactor: number; repetitions: number; }>.memoryState: Readonly<{
    interval: number;
    easeFactor: number;
    repetitions: number;
}> | null
memoryState
,
ModelStepInput<{ interval: number; easeFactor: number; repetitions: number; }>.rating: 1 | 2 | 3 | 4
rating
:
const review: ModelReview
review
.
ModelReview.rating: 1 | 2 | 3 | 4
rating
,
ModelStepInput<{ interval: number; easeFactor: number; repetitions: number; }>.elapsedDays: number
elapsedDays
:
const review: ModelReview
review
.
ModelReview.deltaT: number
deltaT
,
})
const states: {
    interval: number;
    easeFactor: number;
    repetitions: number;
}[]
states
.push(memoryState)
} return
const states: {
    interval: number;
    easeFactor: number;
    repetitions: number;
}[]
states
} return {
ModelCore<{ readonly config: { weights: [number, number, number, number, number, number]; }; readonly memoryState: { interval: number; easeFactor: number; repetitions: number; }; readonly algorithm: null; }>.config: {
    weights: [number, number, number, number, number, number];
}
config
: parsed,
ModelCore<{ readonly config: { weights: [number, number, number, number, number, number]; }; readonly memoryState: { interval: number; easeFactor: number; repetitions: number; }; readonly algorithm: null; }>.bounds: ModelBoundsShape<{
    interval: number;
    easeFactor: number;
    repetitions: number;
}>
bounds
: {
iMin: 0.01, iMax: 36500, eMin: 1.3, eMax: 10, rMin: 0, rMax: Infinity, },
ModelCore<{ readonly config: { weights: [number, number, number, number, number, number]; }; readonly memoryState: { interval: number; easeFactor: number; repetitions: number; }; readonly algorithm: null; }>.algorithm: null
algorithm
: null,
ModelCore<{ readonly config: { weights: [number, number, number, number, number, number]; }; readonly memoryState: { interval: number; easeFactor: number; repetitions: number; }; readonly algorithm: null; }>.step: (input: ModelStepInput<{
    interval: number;
    easeFactor: number;
    repetitions: number;
}>) => {
    interval: number;
    easeFactor: number;
    repetitions: number;
}
step
,
// Invert the benchmark curve to satisfy the Model interval contract.
ModelCore<{ readonly config: { weights: [number, number, number, number, number, number]; }; readonly memoryState: { interval: number; easeFactor: number; repetitions: number; }; readonly algorithm: null; }>.nextInterval: (memoryState: Readonly<{
    interval: number;
    easeFactor: number;
    repetitions: number;
}>, desiredRetention: number) => number
nextInterval
: (state: Readonly<
type MemoryState = {
    interval: number;
    easeFactor: number;
    repetitions: number;
}
MemoryState
>, desiredRetention: number) =>
Math.max( 1, Math.round( (state.interval * Math.log(desiredRetention)) / Math.log(0.9) ) ),
ModelCore<{ readonly config: { weights: [number, number, number, number, number, number]; }; readonly memoryState: { interval: number; easeFactor: number; repetitions: number; }; readonly algorithm: null; }>.forgettingCurve: (memoryState: Readonly<{
    interval: number;
    easeFactor: number;
    repetitions: number;
}>, elapsedDays: number) => number
forgettingCurve
: (state: Readonly<
type MemoryState = {
    interval: number;
    easeFactor: number;
    repetitions: number;
}
MemoryState
>, elapsedDays: number) =>
0.9 ** (elapsedDays / state.interval),
ModelCore<{ readonly config: { weights: [number, number, number, number, number, number]; }; readonly memoryState: { interval: number; easeFactor: number; repetitions: number; }; readonly algorithm: null; }>.forward: (input: ModelForwardInput<{
    interval: number;
    easeFactor: number;
    repetitions: number;
}>) => readonly {
    interval: number;
    easeFactor: number;
    repetitions: number;
}[]
forward
,
} }, }) const
const model: ModelCore<{
    readonly config: {
        weights: [number, number, number, number, number, number];
    };
    readonly memoryState: {
        interval: number;
        easeFactor: number;
        repetitions: number;
    };
    readonly algorithm: null;
}>
model
=
const SM2Model: Model<{
    readonly name: "sm2";
    readonly config: z.ZodObject<{
        weights: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
    }, z.core.$strip>;
    readonly memoryState: z.ZodObject<{
        interval: z.ZodNumber;
        easeFactor: z.ZodNumber;
        repetitions: z.ZodNumber;
    }, z.core.$strip>;
    readonly algorithm: null;
}>
SM2Model
.
Model<{ readonly name: "sm2"; readonly config: ZodObject<{ weights: ZodTuple<[ZodNumber, ZodNumber, ZodNumber, ZodNumber, ZodNumber, ZodNumber], null>; }, $strip>; readonly memoryState: ZodObject<...>; readonly algorithm: null; }>.create: (ctx: {
    readonly config: {
        weights: [number, number, number, number, number, number];
    } | {
        weights: [number, number, number, number, number, number];
    };
    readonly migrate?: boolean;
    readonly clip?: boolean;
    readonly check?: boolean;
    readonly bypass?: boolean;
}) => ModelCore<{
    readonly config: {
        weights: [number, number, number, number, number, number];
    };
    readonly memoryState: {
        interval: number;
        easeFactor: number;
        repetitions: number;
    };
    readonly algorithm: null;
}>
create
({
config: { weights: [1, 6, 2.5, 0.02, 7, 0.18] }, }) const
const states: readonly {
    interval: number;
    easeFactor: number;
    repetitions: number;
}[]
states
=
const model: ModelCore<{
    readonly config: {
        weights: [number, number, number, number, number, number];
    };
    readonly memoryState: {
        interval: number;
        easeFactor: number;
        repetitions: number;
    };
    readonly algorithm: null;
}>
model
.
ModelCore<{ readonly config: { weights: [number, number, number, number, number, number]; }; readonly memoryState: { interval: number; easeFactor: number; repetitions: number; }; readonly algorithm: null; }>.forward: (input: ModelForwardInput<{
    interval: number;
    easeFactor: number;
    repetitions: number;
}>) => readonly {
    interval: number;
    easeFactor: number;
    repetitions: number;
}[]
forward
({
ModelForwardInput<{ interval: number; easeFactor: number; repetitions: number; }>.history: readonly ModelReview[]
history
: [
{
ModelReview.rating: 1 | 2 | 3 | 4
rating
:
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Good,
ModelReview.deltaT: number
deltaT
: 0 },
{
ModelReview.rating: 1 | 2 | 3 | 4
rating
:
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Good,
ModelReview.deltaT: number
deltaT
: 1 },
{
ModelReview.rating: 1 | 2 | 3 | 4
rating
:
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Good,
ModelReview.deltaT: number
deltaT
: 6 },
{
ModelReview.rating: 1 | 2 | 3 | 4
rating
:
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Again,
ModelReview.deltaT: number
deltaT
: 15 },
{
ModelReview.rating: 1 | 2 | 3 | 4
rating
:
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Good,
ModelReview.deltaT: number
deltaT
: 1 },
{
ModelReview.rating: 1 | 2 | 3 | 4
rating
:
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Good,
ModelReview.deltaT: number
deltaT
: 1 },
], }) console.log(JSON.stringify(
const states: readonly {
    interval: number;
    easeFactor: number;
    repetitions: number;
}[]
states
, null, 2)) // Intervals: 1, 6, 15, 1, 1, 6 days.

Schema は public 境界を記述し、scheduler が schema を合成するときに使われます。create を直接呼び出す場合、具体的な実装は必要な解析と正規化を済ませてから config、bounds、algorithm、step、nextInterval、forgettingCurve、forward を返す必要があります。このコアは決定論的に保ち、スケジューリングポリシーを含めません。

bypass は準備済みの設定だけに使う

呼び出し側が対象モデルの migrate、clip、schema 検証、範囲検査を明示的に完了している場合に限り、FSRS6Model.create({ config, bypass: true }) を使えます。create 時のこれらの処理と freeze は省略されます。ユーザー入力、ストレージ、ネットワークから得た未検証の設定には bypass を使わないでください。

モデルバージョン

  • FSRS-7 — 二成分の実装リファレンス。34 個の重みと数値的な間隔計算。
  • FSRS-6 — 学習可能な減衰と同日更新を備えます。
  • FSRS-5 — 固定のべき忘却曲線と同日更新を使います。
  • FSRS-4.5 — 固定のべき曲線を使い、同日更新の数式はありません。
  • FSRS-4 — この package で最初にべき曲線を採用したバージョンです。
  • FSRS-3 — 以前の指数忘却曲線を使います。