> 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.

# モデル概要

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

このセクションの FSRS-3 から FSRS-6 の用語と数式は [awesome-fsrs Wiki](https://github.com/open-spaced-repetition/awesome-fsrs/wiki)、特に [The Algorithm](https://github.com/open-spaced-repetition/awesome-fsrs/wiki/The-Algorithm) を基準に確認しています。TypeScript API とフレームワークの責務境界は ts-fsrs 自体に基づきます。

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


For your Agent

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

Prompt をコピー

現在の ts-fsrs Model 契約を使って、次のタスクに対応してください：[タスクを記述]。

1. https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/index.md と、選択したモデルバージョンのページを読む。
2. 必要に応じて、FSRS-6（https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-6.md）、FSRS-5（https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-5.md）、FSRS-4.5（https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-4dot5.md）、FSRS-4（https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-4.md）、FSRS-3（https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-3.md）の数式と説明を参照する。 FSRS-7: https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-7.md.
3. モデルを実装する前に、設定 schema と記憶状態 schema を定義する。
4. モデルの責務を step、nextInterval、forgettingCurve、forward に限定する。
5. nextInterval には目標保持率を明示的に渡す。
6. scheduler に復習処理を統括させ、chrono に時間を扱わせ、middleware に学習ステップ、ファジング、最大間隔、キュー状態のポリシーを適用させる。
7. 設定の migrate、clip、check が完了した後にだけ bypass を使う。
8. 現在の public API を使い、実装した各数式に焦点を絞ったテストを追加する。

## 共通の記号

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

[FSRS-7](https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-7.md) は実装のスナップショットを基に別途説明します。速い安定度を追加し、混合曲線を使って小数の日数の間隔を返します。上表の安定度の 90% 定義と `I(r, S)` の記法は FSRS-3〜6 に適用されます。

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

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

```ts twoslash file="../../../snippets/run-code/model.ts"
import { Rating } from 'ts-fsrs'
import { FSRS6_DEFAULT_WEIGHTS, FSRS6Model } from 'ts-fsrs/models/fsrs-6'

const model = FSRS6Model.create({
  config: {
    weights: FSRS6_DEFAULT_WEIGHTS,
    enableShortTerm: true,
    numRelearningSteps: 1, // Constrains weights; middleware runs the steps.
  },
})

const memoryState = model.step({
  memoryState: null,
  rating: Rating.Good,
  elapsedDays: 0,
})
const desiredRetention = 0.9
const interval = model.nextInterval(memoryState, desiredRetention)
const retrievabilityAtInterval = model.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 の派生版](https://github.com/open-spaced-repetition/srs-benchmark/blob/main/models/sm2_trainable.py) を実装し、モデルの定義方法を示します。

```ts twoslash fold height=420 file="../../../snippets/run-code/custom-model.ts"
import {
  clamp,
  defineModel,
  type ModelForwardInput,
  type ModelStepInput,
  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 MemoryState = z.output<typeof memoryStateSchema>

const SM2Model = defineModel({
  name: 'sm2',
  schema: { config: configSchema, memoryState: memoryStateSchema },
  defaultValue: {
    memoryState: ({ config }) => ({
      interval: 0,
      easeFactor: config.weights[2],
      repetitions: 0,
    }),
  },
  create({ config }) {
    const parsed = configSchema.parse(config)
    const w = parsed.weights
    const step = ({ memoryState, rating }: ModelStepInput<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 > Rating.Again ? previous.repetitions + 1 : 0
      const interval = clamp(
        repetitions <= 1
          ? w[0]
          : repetitions === 2
            ? w[1]
            : previous.interval * previous.easeFactor,
        0.01,
        36500
      )
      const easeFactor = clamp(
        previous.easeFactor - w[3] * (quality - w[4]) ** 2 + w[5],
        1.3,
        10
      )
      return { interval, easeFactor, repetitions }
    }
    const forward = ({
      history,
      initialState,
    }: ModelForwardInput<MemoryState>) => {
      const states: MemoryState[] = []
      let memoryState = initialState ?? null
      for (const review of history) {
        memoryState = step({
          memoryState,
          rating: review.rating,
          elapsedDays: review.deltaT,
        })
        states.push(memoryState)
      }
      return states
    }
    return {
      config: parsed,
      bounds: {
        iMin: 0.01,
        iMax: 36500,
        eMin: 1.3,
        eMax: 10,
        rMin: 0,
        rMax: Infinity,
      },
      algorithm: null,
      step,
      // Invert the benchmark curve to satisfy the Model interval contract.
      nextInterval: (state: Readonly<MemoryState>, desiredRetention: number) =>
        Math.max(
          1,
          Math.round(
            (state.interval * Math.log(desiredRetention)) / Math.log(0.9)
          )
        ),
      forgettingCurve: (state: Readonly<MemoryState>, elapsedDays: number) =>
        0.9 ** (elapsedDays / state.interval),
      forward,
    }
  },
})

const model = SM2Model.create({
  config: { weights: [1, 6, 2.5, 0.02, 7, 0.18] },
})
const states = model.forward({
  history: [
    { rating: Rating.Good, deltaT: 0 },
    { rating: Rating.Good, deltaT: 1 },
    { rating: Rating.Good, deltaT: 6 },
    { rating: Rating.Again, deltaT: 15 },
    { rating: Rating.Good, deltaT: 1 },
    { rating: Rating.Good, deltaT: 1 },
  ],
})
console.log(JSON.stringify(states, null, 2)) // Intervals: 1, 6, 15, 1, 1, 6 days.

```


▶ コードを実行

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

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

## モデルバージョン

- [FSRS-7](https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-7.md) — 二成分の実装リファレンス。34 個の重みと数値的な間隔計算。
- [FSRS-6](https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-6.md) — 学習可能な減衰と同日更新を備えます。
- [FSRS-5](https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-5.md) — 固定のべき忘却曲線と同日更新を使います。
- [FSRS-4.5](https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-4dot5.md) — 固定のべき曲線を使い、同日更新の数式はありません。
- [FSRS-4](https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-4.md) — この package で最初にべき曲線を採用したバージョンです。
- [FSRS-3](https://open-spaced-repetition.github.io/ts-fsrs/ja-JP/guide/model/fsrs-3.md) — 以前の指数忘却曲線を使います。
