SuperMemo(SM-2)的间隔重复算法

为了在Android中创建词汇练习应用程序,我想在Java中实现SuperMemo(SM-2)算法 。 这是间隔重复软件的流行选择,Anki甚至按照我的理解采用它。 这里给出的源代码示例很难(对我来说)因为缺少代码格式化而且因为它是用Delphi编写的。

SuperMemo的作者说 :

  1. 将知识分成尽可能小的项目。
  2. 所有项目关联的E因子等于2.5。
  3. 使用以下间隔重复项目:I(1):= 1
    I(2):= 6
    对于n> 2:I(n):= I(n-1)* EF
    哪里:
    I(n) – 第n次重复后的重复间隔(以天为单位),
    EF – 给定项目的E因子
    如果interval是分数,则将其四舍五入为最接近的整数。
  4. 每次重复后,评估0-5等级的重复反应质量:5 – 完美的反应
    4 – 犹豫后的正确回应
    3 – 正确回答的问题非常困难
    2 – 不正确的回应; 正确的一个似乎很容易回忆起来
    1 – 反应不正确; 记得正确的人
    0 – 完全停电。
  5. 每次重复后,根据以下公式修改最近重复项目的E因子:
    EF’:= EF +(0.1-(5-Q)*(0.08+(5-Q)* 0.02))
    哪里:
    EF’ – E因子的新价值,
    EF – E因子的旧值,
    q – 0-5等级的响应质量。
    如果EF小于1.3,那么让EF为1.3。
  6. 如果质量响应低于3,则从头开始重复项目,而不更改E因子(即使用间隔I(1),I(2)等,就像项目被重新记忆一样)。
  7. 在给定日期的每次重复会话之后,再次重复质量评估中得分低于4的所有项目。 继续重复,直到所有这些项目得分至少为4。

以下是Stack Overflow的一些相关(但不同)的问题:

  • 什么是间隔重复算法来生成日间隔?
  • Java中的Spaced重复算法的开源实现
  • 用于学习的间隔重复(SRS)

你是如何用Java实现的?

(我最近一直在研究这个问题,我想我有一个答案,所以我提交这个作为Q&A对来帮助其他人做同样的事情。)

SuperMemo算法

以下是我们将在强制间隔重复的SuperMemo(SM-2)算法时要处理的一些术语。

  • 重复 – 这是用户看到闪卡的次数。 0表示他们尚未研究过, 1表示这是他们的第一次,依此类推。 在一些文档中它也被称为n
  • 质量 – 也称为评估质量。 这是闪存卡的难度(由用户定义)。 比例从05
  • 容易度 – 这也称为容易因子或EFactor或EF。 它是乘数,用于增加间隔重复的“空间”。 范围从1.32.5
  • interval – 这是重复之间的时间长度(以天为单位)。 它是间隔重复的“空间”。
  • nextPractice – 这是闪卡随后再次审核的日期/时间 。

默认值

 int repetitions = 0; int interval = 1; float easiness = 2.5; 

我发现这个Python实现比SuperMemo示例源代码更容易理解,因此我或多或少地遵循它。

 private void calculateSuperMemo2Algorithm(FlashCard card, int quality) { if (quality < 0 || quality > 5) { // throw error here or ensure elsewhere that quality is always within 0-5 } // retrieve the stored values (default values if new cards) int repetitions = card.getRepetitions(); float easiness = card.getEasinessFactor(); int interval = card.getInterval(); // easiness factor easiness = (float) Math.max(1.3, easiness + 0.1 - (5.0 - quality) * (0.08 + (5.0 - quality) * 0.02)); // repetitions if (quality < 3) { repetitions = 0; } else { repetitions += 1; } // interval if (repetitions <= 1) { interval = 1; } else if (repetitions == 2) { interval = 6; } else { interval = Math.round(interval * easiness); } // next practice int secondsInDay = 60 * 60 * 24; long now = System.currentTimeMillis(); long nextPracticeDate = now + secondsInDay*interval; // Store the nextPracticeDate in the database // ... } 

笔记

  • 上面的代码没有设置easiness上限。 应该是2.5吗? 文档和源代码似乎互相矛盾。
  • 如果质量评估小于3,文档也听起来似乎不应该更新容易因素,但这似乎与源代码相矛盾。 在我看来,更新它更有意义(只要它保持在1.3以上)。 无论如何,我每次都在更新它。
  • Anki源代码在这里 。 不过,这是一个很大的项目,我还没有深入挖掘它们的算法版本。
  • 这篇文章讨论了SM-2的一些问题以及这些问题的解决方案。