- Published on
间隔重复记忆之SM-2
- Authors
- Name
- 万码皆空
最近读了一篇彼得·沃兹尼亚克博士(Dr Piotr Wozniak)写的文章,介绍间隔重复记忆法的历史,文章地址:The true history of spaced repetition。我还没有读完,读到了Algorithm SM-2。
SM-2算法
SM-2是间隔重复记忆的第一代算法,目前还有很多软件在使用,内容如下:
将知识点拆分成最小单元。
将每个知识点分配一个E-Factor,初始值2.5。
使用以下公式重复记忆知识点:
I(1):=1
I(2):=6
for n>2: I(n):=I(n-1)*EF
其中:
I(n)
代表第n次重复记忆时的间隔天数EF
代表每个知识点关联的E-Factor。如果计算出来的间隔时间是小数,四舍五入取整。
每次重复一个知识点后,给出一个记忆质量值,取值范围在0-5:
- 5 - 知识点完全记住。
- 4 - 能回忆起来,略有迟疑。
- 3 - 能回忆起来,但是有难度。
- 2 - 回忆错误,但是正确答案好像很容易能记起来。
- 1 - 回忆错误,但是正确答案记住了。
- 0 - 回忆不起来。
每次重复一个知识点后,更新其关联的E-Factor值,新的E-Factor计算公式如下:
EF’:=EF+(0.1-(5-q)*(0.08+(5-q)*0.02))
其中:
EF’
代表新的E-Factor值。EF
代表就得E-Factor值。q
代表步骤4中给出的记忆质量值。如果
EF’
值小于1.3,则EF’=1.3
如果第4步中的记忆质量值小于3,则该知识点按新知识重新计算间隔记忆。
每一天的重复记忆中记忆质量小于4的知识点需要再次重复,直到记忆质量大于等于4再结束当天的重复记忆过程。
TypeScript实现
export interface SM2Item {
interval?: number,
count?: number,
efactor?: number,
quality: number,
}
export interface SM2Result {
item: SM2Item,
needRepeat: boolean,
}
/**
* Calculates the E-factor of a given quality.
*
* @param {number} efactor - The E-factor to calculate.
* @param {number} quality - The quality to use in the calculation.
* @return {number} The calculated E-factor.
*/
function calculateEFactor(efactor: number, quality: number): number {
let nextEFactor = efactor + (0.1 - (5 - quality) * (0.08 + (5 - quality) * 0.02));
if (nextEFactor > 2.5) return 2.5;
else if (nextEFactor < 1.3) return 1.3;
else return Number(nextEFactor.toFixed(3));
}
/**
* Calculates the result of multiplying an interval by an efactor.
*
* @param {number} interval - The interval to be multiplied.
* @param {number} efactor - The efactor to multiply the interval by.
* @return {number} The result of the multiplication.
*/
function calculateInterval(interval: number, efactor: number): number {
return Math.round(interval * efactor);
}
/**
* Calculates the next interval and other values for a given SM2Item, based on its
* current values. If the quality is less than 4, the item is marked for repetition.
*
* @param {SM2Item} item - the SM2Item to calculate the next interval for
* @return {SM2Result} an object with the next SM2Item and a boolean indicating if the item needs to be repeated
*/
function sm2(item: SM2Item): SM2Result {
let { interval = 1, count = 1, efactor = 2.5, quality } = item;
if (interval < 1) interval = 1;
if (count < 1) count = 1;
if (efactor < 1.3) efactor = 1.3;
if (efactor > 2.5) efactor = 2.5;
if (quality < 0) quality = 0;
if (quality > 5) quality = 5;
const needRepeat: boolean = quality < 4;
const nextItem: SM2Item = {
interval,
count,
efactor,
quality,
};
if (quality < 3) {
nextItem.interval = 1;
nextItem.count = 1;
nextItem.efactor = 2.5;
} else {
switch (count) {
case 1:
nextItem.interval = 1;
break;
case 2:
nextItem.interval = 6;
break;
default:
nextItem.interval = calculateInterval(interval, efactor);
break;
}
nextItem.count = count + 1;
nextItem.efactor = calculateEFactor(efactor, quality);
}
return { item: nextItem, needRepeat }
}
export default sm2;
使用实例:
import sm2, { SM2Item } from '../src/sm2';
interface Card {
question: string,
answer: string,
interval?: number,
count?: number,
efactor?: number,
};
function getCardsFromSomewhere(): Card[] {
const cards: Card[] = [
{ question: 'a', answer: 'A' },
{ question: 'b', answer: 'B', interval: 1, count: 1, efactor: 2.5 },
{ question: 'c', answer: 'C', interval: 6, count: 2, efactor: 1.8 },
{ question: 'd', answer: 'D', interval: 8, count: 3, efactor: 1.3 },
{ question: 'e', answer: 'E', interval: 16, count: 4, efactor: 2.1 },
];
return cards;
}
function getQualityFromUserResponse(card: Card): number {
return Math.round(Math.random() * 5);
}
function updateCard(card: Card, item: SM2Item) {
const { interval, count, efactor } = item;
const cardUpdated: Card = { ...card, interval, count, efactor };
console.log('card with new sm info', cardUpdated);
}
function main() {
const cards = getCardsFromSomewhere();
for (const card of cards) {
const { interval, count, efactor } = card;
const quality = getQualityFromUserResponse(card);
const {item, needRepeat} = sm2({ interval, count, efactor, quality });
updateCard(card, item);
if(needRepeat) {
console.log('Card need to remember again today until quality >= 4.', card);
}
}
}
main();
NPM
已经发布到了npm,可以直接安装使用:
npm install spaced-repetition.js
GITHUB
Github仓库地址:spaced-repetition.js