Ankiのスケジューリングアルゴリズムについて

Ankiのソースコードはこちらに公開されているが、これをもとにアルゴリズムを読み解くのは一筋縄ではいかない。
別サイトにて、アルゴリズムを噛み砕いてシンプルなPythonコードに落としてくれたものがあったため、これをもとにスケジューリング規則の理解を深めた。

以下、コードそのままの説明ではあるが、Anki初心者にとっては各種設定値の理解に繋がると思い、コードの解釈を書き下ろしてみた。

デッキオプションとカード内部の値

デッキオプションの画面で任意に変更できる、各設定値は以下のような用語で定義する。

# "New Cards" tab
NEW_STEPS = [1, 10]  # in minutes (学習ステップ)
GRADUATING_INTERVAL = 1  # in days (最終ステップから復習開始までの間隔)
EASY_INTERVAL = 4  # in days (「簡単」と回答してから復習開始までの間隔 )
STARTING_EASE = 250  # in percent (復習開始時の間隔の伸び率)

# "Reviews" tab
EASY_BONUS = 130  # in percent (「簡単」と回答した時のボーナス)
INTERVAL_MODIFIER = 100  # in percent (復習ペースの調整)
MAXIMUM_INTERVAL = 36500  # in days (復習間隔の上限)

# "Lapses" tab
LAPSES_STEPS = [10]  # in minutes (再学習ステップ)
NEW_INTERVAL = 70  # in percent (新しい復習間隔(前回比))
MINIMUM_INTERVAL = 1  # in days (忘却カードの復習開始までの間隔)

また、1つ1つのカードは、次のような4つの値を内部に持っている。

self.status = 'learning'
self.steps_index = 0
self.ease_factor = STARTING_EASE
self.interval = None
  • ステータス: ’learning'(学習中), ‘learned'(復習中), ‘relearning'(再学習中)のいずれかの値をとる
  • ステップ数: 「学習中」「再学習中」プロセスにおける何ステップにいるか
  • 簡単さ: 「復習開始時の間隔の伸び率」(250%)が初期値となる
  • 復習間隔

「復習中」カードについて

まず、一番わかりやすい「復習中」のカードについて考える。
復習中のカードに対して、「やり直し」「難しい」「普通」「簡単」の4つの選択肢が与えられる。

# 「復習中(learned)」カードの場合
if response == "hard":  
    card.ease_factor = max(130, card.ease_factor - 15)  
    card.interval = card.interval * 1.2 * INTERVAL_MODIFIER/100  
    return min(MAXIMUM_INTERVAL, card.interval)  
elif response == "good":
    card.interval = (card.interval * card.ease_factor/100 * INTERVAL_MODIFIER/100)
    return min(MAXIMUM_INTERVAL, card.interval)
elif response == "easy":
    card.ease_factor += 15
    card.interval = (card.interval * card.ease_factor/100 * INTERVAL_MODIFIER/100 * EASY_BONUS/100)
    return min(MAXIMUM_INTERVAL, card.interval)

復習中のカードに対して、・・・
「難しい」と解答すると、
①カードの簡単さ(ease factor)が最小130%になるまで15%ずつ減る
②カードの復習間隔値が、前回の復習間隔 × 1.2倍 × INTERVAL_MODIFIER の値となる。
③最大の復習間隔に達するまで②が次の復習間隔となる。

「普通」と解答すると、
カードの簡単さ(ease factor)は変化しない
②カードの復習間隔値が、前回の復習間隔 × 簡単さ(ease factor) × INTERVAL_MODIFIER の値となる。
③最大の復習間隔に達するまで、②が次の復習間隔となる。

「簡単」と解答すると、
カードの簡単さ(ease factor)が15%ずつ増える
②カードの復習間隔値が、前回の復習間隔 × 簡単さ(ease factor) × INTERVAL_MODIFIER × EASY_BONUS の値となる。
最大の復習間隔に達するまで、②が次の復習間隔となる。

もし「やり直し」を選択した場合は、以下のようになる。

if response == "again":
    card.status = 'relearning'
    card.steps_index = 0
    card.ease_factor = max(130, card.ease_factor - 20)
    card.interval = max(MINIMUM_INTERVAL, card.interval * NEW_INTERVAL/100)
    return minutes_to_days(LAPSES_STEPS[0])

すなわち、
①カードのステータスが「再学習中」に変わる。
②再学習ステップの1ステップ目に配置される。
③簡単さ(ease factor)が最小でも130%になるまで20%引かれる
④復習間隔値が、最小でもMINIMUM_INTERVAL(忘却カードの復習開始までの間隔)になるまで、前回の復習間隔 × NEW_INTERVAL(新しい復習間隔の比率)の値となる。

「再学習中」カードについて ※後日修正

    elif card.status == 'relearning':
        if response == "again":
            card.steps_index = 0
            return minutes_to_days(LAPSE_STEPS[0])
        elif response == "good":
            card.steps_index += 1
            if card.steps_index < len(LAPSE_STEPS):
                return minutes_to_days(LAPSE_STEPS[card.steps_index])
            else:
                # we have re-graduated!
                card.status = 'learned'
                # we don't modify the interval here because that was already done when
                # going from 'learned' to 'relearning'
                return card.interval

「学習中」カードについて ※後日修正

    if card.status == 'learning':
        # for learning cards, there is no "hard" response possible
        if response == "again":
            card.steps_index = 0
            return minutes_to_days(NEW_STEPS[card.steps_index])
        elif response == "good":
            card.steps_index += 1
            if card.steps_index < len(NEW_STEPS):
                return minutes_to_days(NEW_STEPS[card.steps_index])
            else:
                # we have graduated!
                card.status = 'learned'
                card.interval = GRADUATING_INTERVAL
                return card.interval
        elif response == "easy":
            card.status = 'learned'
            card.interval = EASY_INTERVAL
            return EASY_INTERVAL

コメントする

メールアドレスが公開されることはありません。

CAPTCHA