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

2022-09-03 16:53:13

为了在Android中制作一个词汇练习应用程序,我想在Java中实现SuperMemo(SM-2)算法。这是间隔重复软件的热门选择,Anki甚至采用了我的理解。这里给出的源代码示例(对我来说)很难遵循,因为缺乏代码格式,因为它是用Delphi编写的。

SuperMemo的作者指出

  1. 将知识拆分为尽可能小的项目。
  2. 对于所有项目,E 因子的 E 因子等于 2.5。
  3. 使用以下间隔重复项目: I(1):=1
    I(2):=6
    表示 n>2: I(n):=I(n-1)*EF
    其中:
    I(n) - 第 n 次重复(以天为单位)之后的重复间隔,
    EF - 给定项目的
    E 因子 如果间隔是分数,则将其向上舍入为最接近的整数。
  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. 在给定日期的每个重复会话之后,再次重复所有在质量评估中得分低于四的项目。继续重复,直到所有这些项目都至少获得四分。

以下是有关堆栈溢出的一些相关(但不同)问题:

你如何在Java中实现它?

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


答案 1

超级备忘录算法

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

  • 重复 - 这是用户看到抽认卡的次数。 意味着他们还没有研究过它,意味着这是他们的第一次,等等。在某些文档中也称为它。01n
  • 质量 - 也称为评估质量。这就是抽认卡的难度(由用户定义)。比例尺为 从 到 。05
  • 易用性 - 这也称为易用性因子或 EFactor 或 EF。它是用于增加间隔重复中“空间”的乘数。范围是从 到 。1.32.5
  • 间隔 - 这是重复之间的时间长度(以天为单位)。它是间隔重复的“空间”。
  • 下一步实践 - 这是抽认卡再次进行审查的日期/时间

默认值

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 millisecondsInDay = 60 * 60 * 24 * 1000;
    long now = System.currentTimeMillis();
    long nextPracticeDate = now + millisecondsInDay*interval;

    // Store the nextPracticeDate in the database
    // ...
}

笔记

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

答案 2