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

Sur*_*gch 7 java algorithm android

为了在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实现的?

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

Sur*_*gch 16

SuperMemo算法

这里有一些条款,我们会处理impementing的时候用的SuperMemo(SM-2)算法间隔重复.

  • 重复 - 这是用户看到闪卡的次数.0意味着他们还没有研究过,1意味着这是他们的第一次,等等.n在一些文档中也称为它.
  • 质量 - 也称为评估质量.这是闪存卡的难度(由用户定义).规模从.05.
  • 容易度 - 这也称为容易因子或EFactor或EF.它是乘数,用于增加间隔重复的"空间".范围是从.1.32.5.
  • interval - 这是重复之间的时间长度(以天为单位).它是间隔重复的"空间".
  • nextPractice - 这是闪卡随后再次审核的日期/时间.

默认值

int repetitions = 0;
int interval = 1;
float easiness = 2.5;
Run Code Online (Sandbox Code Playgroud)

我发现这个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;
    long now = System.currentTimeMillis();
    long nextPracticeDate = now + millisecondsInDay*interval;

    // Store the nextPracticeDate in the database
    // ...
}
Run Code Online (Sandbox Code Playgroud)

笔记

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