Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
72 views12 pages

SM-2 Spaced Repetition Algorithm - Developer's Guide

SM-2 Spaced Repetition Algorithm

Uploaded by

onlykf069
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
72 views12 pages

SM-2 Spaced Repetition Algorithm - Developer's Guide

SM-2 Spaced Repetition Algorithm

Uploaded by

onlykf069
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

SM-2 Spaced Repetition Algorithm

Complete Implementation Guide for Developers


What is SM-2?
SM-2 (SuperMemo 2) is the algorithm that revolutionized computer-assisted learning in 1987. It's the
grandfather of most modern spaced repetition systems, including Anki's default algorithm. The core
idea: calculate the optimal time to review information just before you're about to forget it.

📐 The Core Algorithm


Key Variables
javascript
// For each piece of information you track:
{
n: 0, // Repetition number (how many times reviewed)
EF: 2.5, // Easiness Factor (how easy the item is for you)
I: 1, // Inter-repetition interval (days until next review)
lastReview: Date, // When last reviewed
nextReview: Date // When to review next
}

The SM-2 Formula


javascript
function calculateNextInterval(quality, n, EF, I) {
// quality: Your self-assessment (0-5 scale)
// 0 - Complete blackout
// 1 - Incorrect, but recognized when shown answer
// 2 - Incorrect, but felt close
// 3 - Correct, but difficult recall
// 4 - Correct, with hesitation
// 5 - Perfect recall
// Step 1: Calculate new Easiness Factor
let newEF = EF + (0.1 - (5 - quality) * (0.08 + (5 - quality) * 0.02));
// Keep EF bounded (minimum 1.3 for hardest items)
if (newEF < 1.3) newEF = 1.3;
// Step 2: Calculate next interval
let newInterval;
if (quality < 3) {
// Failed recall - reset to beginning
newInterval = 1;
n = 0;
} else {
// Successful recall - increase interval
if (n === 0) {
newInterval = 1;
} else if (n === 1) {
newInterval = 6;
} else {
newInterval = Math.round(I * newEF);
}
n = n + 1;
}
return {
interval: newInterval,
EF: newEF,
repetition: n
};
}
🎯 How It Actually Works
Example Learning Journey
Let's say you're learning the concept "React Hooks useEffect cleanup function":
Day 0 (First Learning)
You learn it for the first time
Initial values: EF = 2.5 , n = 0 , I = 1
Next review: Tomorrow
Day 1 (First Review)
You recall it correctly but with hesitation (quality = 4)
New EF: 2.5 + (0.1 - 1 * 0.1) = 2.5 (unchanged)
Next interval: 6 days
Next review: Day 7
Day 7 (Second Review)
Perfect recall (quality = 5)
New EF: 2.5 + 0.1 = 2.6 (gets easier)
Next interval: 6 * 2.6 = 15.6 ≈ 16 days
Next review: Day 23
Day 23 (Third Review)
Struggled but got it (quality = 3)
New EF: 2.6 + (0.1 - 2 * 0.12) = 2.46
Next interval: 16 * 2.46 = 39.36 ≈ 39 days
Next review: Day 62

💻 Complete JavaScript Implementation


javascript
class SM2SpacedRepetition {
constructor() {
this.cards = new Map(); // Store all learning items
}
// Add new item to learn
addCard(id, content) {
this.cards.set(id, {
id: id,
content: content,
n: 0,
EF: 2.5,
I: 1,
lastReview: null,
nextReview: new Date(),
history: []
});
}
// Review a card and calculate next review
reviewCard(id, quality) {
const card = this.cards.get(id);
if (!card) throw new Error('Card not found');
// Record the review
const reviewDate = new Date();
card.history.push({
date: reviewDate,
quality: quality,
EF: card.EF,
interval: card.I
});
// Calculate new values
let newEF = card.EF + (0.1 - (5 - quality) * (0.08 + (5 - quality) * 0.02));
newEF = Math.max(1.3, newEF); // Minimum bound
let newInterval;
let newN = card.n;
if (quality < 3) {
// Reset on failure
newInterval = 1;
newN = 0;
} else {
// Progress on success
switch(card.n) {
case 0:
newInterval = 1;
break;
case 1:
newInterval = 6;
break;
default:
newInterval = Math.round(card.I * card.EF);
}
newN = card.n + 1;
}
// Update card
card.n = newN;
card.EF = newEF;
card.I = newInterval;
card.lastReview = reviewDate;
card.nextReview = this.addDays(reviewDate, newInterval);
return {
nextReview: card.nextReview,
interval: newInterval,
easiness: newEF
};
}
// Get cards due for review
getDueCards() {
const now = new Date();
const due = [];
for (const [id, card] of this.cards) {
if (card.nextReview <= now) {
due.push(card);
}
}
// Sort by priority (overdue items first)
return due.sort((a, b) => a.nextReview - b.nextReview);
}
// Helper function
addDays(date, days) {
const result = new Date(date);
result.setDate(result.getDate() + days);
return result;
}
// Get statistics
getStats() {
let total = this.cards.size;
let learned = 0;
let due = 0;
const now = new Date();
for (const card of this.cards.values
values()) {
if (card.n > 0) learned++;
if (card.nextReview <= now) due++;
}
return {
total: total,
learned: learned,
due: due,
retention: learned / total * 100
};
}
}
// Usage Example
const srs = new SM2SpacedRepetition();
// Add a new concept to learn
srs.addCard('react-1', 'useEffect cleanup function returns cleanup logic');
// Review it (quality: 0-5)
const result = srs.reviewCard('react-1', 4); // Correct with hesitation
console.log(`Next review in ${result.interval} days`);

🔧 Custom Modifications for Your Use Case


1. Time-of-Day Optimization
javascript
// Modify intervals based on your schedule
function adjustForSchedule(baseInterval, cardType) {
const adjustments = {
'technical': 1.0, // Review technical stuff normally
'concepts': 1.2, // Give more time for abstract concepts
'commands': 0.8, // Review commands more frequently
'facts': 1.1 // Slightly longer for pure facts
};
return Math.round(baseInterval * (adjustments[cardType] || 1.0));
}

2. Contextual Difficulty Adjustment


javascript
// Adjust EF based on context
function contextualEF(baseEF, context) {
// If reviewed during gym (harder context), boost EF
if (context === 'gym') {
return baseEF * 1.1; // Give credit for harder conditions
}
// If reviewed while tired (after 8pm), adjust
const hour = new Date().getHours();
if (hour >= 20) {
return baseEF * 1.05;
}
return baseEF;
}

3. Workout-Integrated Algorithm
javascript
class WorkoutSRS extends SM2SpacedRepetition {
reviewCard(id, quality, context = {}) {
// Track where review happened
const location = context.location || 'default';
const energy = context.energyLevel || 'normal';
// Adjust quality based on context
let adjustedQuality = quality;
if (location === 'gym' && quality >= 3) {
// Successful recall at gym = bonus
adjustedQuality = Math.min(5, quality + 0.5);
}
if (energy === 'tired' && quality >= 3) {
// Successful recall when tired = bonus
adjustedQuality = Math.min(5, quality + 0.3);
}
return super.reviewCard(id, adjustedQuality);
}
}

📊 Alternative Algorithms to Consider


1. SM-18 (Latest SuperMemo)
More sophisticated but complex
Considers time of day, sleep quality
Better for long-term retention
2. FSRS (Free Spaced Repetition Scheduler)
javascript
// Simplified FSRS - Better than SM-2 for most cases
function FSRS(difficulty, stability, retrievability) {
// Uses machine learning principles
const optimalInterval = stability * Math.log(0.9) / Math.log(retrievability);
return Math.max(1, Math.round(optimalInterval));
}
3. Custom Hybrid for Developers
javascript
class DeveloperSRS {
calculateInterval(card, quality) {
// Base: SM-2 algorithm
let interval = this.sm2Calculate(card, quality);
// Adjust for information type
if (card.type === 'syntax') {
interval *= 0.7; // See syntax more often
} else if (card.type === 'concept') {
interval *= 1.3; // Concepts need less frequent review
} else if (card.type === 'bug-pattern') {
interval *= 0.5; // Critical to remember
}
// Adjust for source
if (card.source === 'production-bug') {
interval *= 0.6; // Never forget production issues!
}
// Cap based on importance
if (card.importance === 'critical') {
interval = Math.min(interval, 30); // Never go beyond 30 days
}
return interval;
}
}

🎮 Gamification Layer
javascript
class GamifiedSRS extends SM2SpacedRepetition {
constructor() {
super();
this.streaks = new Map();
this.achievements = [];
}
reviewCard(id, quality) {
const result = super.reviewCard(id, quality);
// Track streaks
if (quality >= 3) {
const currentStreak = this.streaks.get(id) || 0;
this.streaks.set(id, currentStreak + 1);
// Check achievements
if (currentStreak === 10) {
this.unlockAchievement('Consistent Learner', id);
}
// Bonus interval for streaks
if (currentStreak > 5) {
result.interval *= 1.1; // 10% bonus for good streaks
}
} else {
this.streaks.set(id, 0); // Reset streak on failure
}
return result;
}
unlockAchievement(name, cardId) {
this.achievements.push({
name: name,
cardId: cardId,
date: new Date()
});
// Could trigger notification here
console.log(`🏆 Achievement Unlocked: ${name}!`);
}
}
🚀 Implementation Tips
1. Start Simple: Begin with basic SM-2, add modifications after 30 days of data
2. Track Everything: Log quality scores, time of day, energy levels
3. Analyze Your Data: After 100+ reviews, analyze your personal forgetting curve
4. Adjust Parameters: Your optimal EF might not be 2.5 - experiment!
5. Mobile Sync: Use IndexedDB for offline, sync when online

📱 Database Schema
sql
-- SQLite schema for mobile app
CREATE TABLE cards (
id TEXT PRIMARY KEY,
content TEXT NOT NULL,
type TEXT,
n INTEGER DEFAULT 0,
ef REAL DEFAULT 2.5,
interval INTEGER DEFAULT 1,
last_review TIMESTAMP,
next_review TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE reviews (
id INTEGER PRIMARY KEY AUTOINCREMENT,
card_id TEXT,
quality INTEGER,
interval_before INTEGER,
interval_after INTEGER,
ef_before REAL,
ef_after REAL,
reviewed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
context JSON,
FOREIGN KEY (card_id) REFERENCES cards(id)
);
-- Index for performance
CREATE INDEX idx_next_review ON cards(next_review);
CREATE INDEX idx_card_reviews ON reviews(card_id, reviewed_at);

The beauty of SM-2 is its simplicity and proven effectiveness. Start with the basic implementation,
then customize based on your learning patterns. After 30 days, you'll have enough data to fine-tune
the algorithm specifically for your brain!

You might also like