Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
233 views
in Technique[技术] by (71.8m points)

java - Spaced repetition algorithm from SuperMemo (SM-2)

In order to make a vocabulary practice app in Android, I want to implement the SuperMemo (SM-2) algorithm in Java. This is a popular choice for spaced repetition software and Anki even adopts it as I understand. The source code example given here was difficult (for me) to follow because of the lack of code formatting and because it is written in Delphi.

The author of SuperMemo states:

  1. Split the knowledge into smallest possible items.
  2. With all items associate an E-Factor equal to 2.5.
  3. Repeat items using the following intervals: I(1):=1
    I(2):=6
    for n>2: I(n):=I(n-1)*EF
    where:
    I(n) - inter-repetition interval after the n-th repetition (in days),
    EF - E-Factor of a given item
    If interval is a fraction, round it up to the nearest integer.
  4. After each repetition assess the quality of repetition response in 0-5 grade scale: 5 - perfect response
    4 - correct response after a hesitation
    3 - correct response recalled with serious difficulty
    2 - incorrect response; where the correct one seemed easy to recall
    1 - incorrect response; the correct one remembered
    0 - complete blackout.
  5. After each repetition modify the E-Factor of the recently repeated item according to the formula:
    EF':=EF+(0.1-(5-q)*(0.08+(5-q)*0.02))
    where:
    EF' - new value of the E-Factor,
    EF - old value of the E-Factor,
    q - quality of the response in the 0-5 grade scale.
    If EF is less than 1.3 then let EF be 1.3.
  6. If the quality response was lower than 3 then start repetitions for the item from the beginning without changing the E-Factor (i.e. use intervals I(1), I(2) etc. as if the item was memorized anew).
  7. After each repetition session of a given day repeat again all items that scored below four in the quality assessment. Continue the repetitions until all of these items score at least four.

Here are some related (but different) questions on Stack Overflow:

How do you implement this in Java?

(I've been working on this recently and I think I have an answer, so I am submitting this as a Q&A pair to help other people doing the same thing.)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

SuperMemo algorithm

Here are some terms that we will deal with when impementing the SuperMemo (SM-2) algorithm of spaced repetition.

  • repetitions - this is the number of times a user sees a flashcard. 0 means they haven't studied it yet, 1 means it is their first time, and so on. It is also referred to as n in some of the documentation.
  • quality - also known as quality of assessment. This is how difficult (as defined by the user) a flashcard is. The scale is from 0 to 5.
  • easiness - this is also referred to as the easiness factor or EFactor or EF. It is multiplier used to increase the "space" in spaced repetition. The range is from 1.3 to 2.5.
  • interval - this is the length of time (in days) between repetitions. It is the "space" of spaced repetition.
  • nextPractice - This is the date/time of when the flashcard comes due to review again.

Default values

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

Code

I found this Python implementation somewhat easier to follow than the SuperMemo example source code, so I am more or less following that.

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

Notes

  • The code above does not set an upper limit on easiness. Should it be 2.5? The documentation and source code seemed to contradict each other.
  • The documentation also made it sound like the easiness factor should not be updated if the quality assessment was less than 3, but this seems to contradict the source code. It also seems to me to make more sense to update it (as long as it is kept above 1.3). Anyway, I am updating it every time.
  • The Anki source code is here. It is a big project, though, and I haven't dug down deep enough yet to see their version of the algorithm.
  • This post talks about some problems with SM-2 and solutions for those problems.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...