or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-ebisu-js

A TypeScript/JavaScript port of the Ebisu spaced repetition algorithm for quiz apps to intelligently handle scheduling

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/ebisu-js@2.1.x

To install, run

npx @tessl/cli install tessl/npm-ebisu-js@2.1.0

index.mddocs/

Ebisu-js

Ebisu-js is a TypeScript/JavaScript port of the Ebisu spaced repetition algorithm that enables quiz applications to intelligently schedule fact reviews. It uses Bayesian statistics to model memory strength, predict recall probabilities, and update models based on quiz results.

Package Information

  • Package Name: ebisu-js
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install ebisu-js

Core Imports

import * as ebisu from "ebisu-js";

For CommonJS:

const ebisu = require("ebisu-js");

Individual imports:

import { 
  defaultModel, 
  predictRecall, 
  updateRecall, 
  modelToPercentileDecay, 
  rescaleHalflife 
} from "ebisu-js";

Basic Usage

import * as ebisu from "ebisu-js";

// Create a default model (24-hour halflife)
const model = ebisu.defaultModel(24); // [4, 4, 24]

// Predict recall probability after 10 hours
const currentRecall = ebisu.predictRecall(model, 10, true); // 0.78...

// Update model after a successful quiz (1/1 correct after 10 hours)
const updatedModel = ebisu.updateRecall(model, 1, 1, 10);

// Check the new halflife
const halflife = ebisu.modelToPercentileDecay(updatedModel); // ~18 hours

Architecture

Ebisu-js is built around several key concepts:

  • Memory Models: 3-tuple arrays [alpha, beta, time] representing Beta distributions of recall probability
  • Bayesian Updates: Quiz results are incorporated using statistical inference to refine memory models
  • Multiple Quiz Types: Support for binary, binomial, and noisy-binary quiz formats
  • Time-based Predictions: Memory decay modeling over arbitrary time periods
  • Mathematical Robustness: Numerical stability with fallback computations and caching

Capabilities

Model Creation

Creates default memory models for newly-learned facts with configurable parameters.

/**
 * Creates default memory model for new facts
 * @param t - Half-life time in consistent units (e.g., hours, days)
 * @param a - Alpha parameter for Beta distribution (default: 4.0)
 * @param b - Beta parameter for Beta distribution (default: same as a)
 * @returns Memory model tuple [alpha, beta, time]
 */
function defaultModel(t: number, a?: number, b?: number): Model;

Usage Examples:

// 24-hour halflife with default confidence (4, 4)
const model1 = ebisu.defaultModel(24);

// 2-hour halflife with higher confidence (6, 6)
const model2 = ebisu.defaultModel(2, 6);

// Custom alpha/beta parameters
const model3 = ebisu.defaultModel(12, 3, 5);

Recall Prediction

Predicts the current recall probability based on elapsed time since last review.

/**
 * Predicts current recall probability from memory model
 * @param prior - Memory model tuple [alpha, beta, time]
 * @param tnow - Time elapsed since last review (same units as model)
 * @param exact - If true returns linear probability (0-1), if false returns log-probability (default: false)
 * @returns Recall probability (linear 0-1 if exact=true, log-probability if exact=false)
 */
function predictRecall(prior: Model, tnow: number, exact?: boolean): number;

Usage Examples:

const model = ebisu.defaultModel(24);

// Get linear probability (0-1 range)
const linearProb = ebisu.predictRecall(model, 12, true); // ~0.64

// Get log-probability (for mathematical efficiency)
const logProb = ebisu.predictRecall(model, 12); // ~-0.44

// Check recall after different time periods
const prob6h = ebisu.predictRecall(model, 6, true);   // ~0.85
const prob48h = ebisu.predictRecall(model, 48, true); // ~0.25

Model Updates

Updates memory models based on quiz results using Bayesian inference. Supports multiple quiz types.

/**
 * Updates memory model based on quiz results using Bayesian inference
 * @param prior - Current memory model tuple [alpha, beta, time]
 * @param successes - Number of successful attempts (0 ≤ successes ≤ total)
 * @param total - Total number of attempts (≥ 1)
 * @param tnow - Time elapsed since last review (same units as model)
 * @param q0 - Probability of passing when forgotten (optional, for noisy-binary quizzes)
 * @param rebalance - Whether to rebalance to halflife (default: true)
 * @param tback - Target time for returned model (optional)
 * @param options - Additional options for numerical optimization
 * @returns Updated memory model tuple
 */
function updateRecall(
  prior: Model,
  successes: number,
  total: number,
  tnow: number,
  q0?: number,
  rebalance?: boolean,
  tback?: number,
  options?: Partial<MinimizeParams>
): Model;

Quiz Types:

  • Binary Quiz: total=1, successes ∈ {0, 1}
  • Binomial Quiz: total>1, successes is integer ∈ [0, total]
  • Noisy-Binary Quiz: total=1, successes is float ∈ [0, 1]

Usage Examples:

const model = ebisu.defaultModel(24);

// Binary quiz - successful after 10 hours
const success = ebisu.updateRecall(model, 1, 1, 10);

// Binary quiz - failed after 6 hours  
const failure = ebisu.updateRecall(model, 0, 1, 6);

// Binomial quiz - 3 out of 5 correct after 12 hours
const partial = ebisu.updateRecall(model, 3, 5, 12);

// Noisy-binary quiz with custom q0
const noisy = ebisu.updateRecall(model, 0.85, 1, 8, 0.2);

// Advanced: disable rebalancing and set custom tolerance
const advanced = ebisu.updateRecall(
  model, 1, 1, 15, 
  undefined, false, undefined, 
  { tolerance: 1e-6 }
);

Time Decay Calculations

Calculates time required for memory to decay to a specific percentile.

/**
 * Calculates time for memory to decay to given percentile
 * @param model - Memory model tuple [alpha, beta, time]
 * @param percentile - Target recall percentile (default: 0.5 for halflife)
 * @param tolerance - Numerical tolerance for root finding (default: 1e-4)
 * @returns Time units until decay reaches percentile
 */
function modelToPercentileDecay(
  model: Model, 
  percentile?: number, 
  tolerance?: number
): number;

Usage Examples:

const model = ebisu.defaultModel(24);

// Get halflife (50% recall probability)
const halflife = ebisu.modelToPercentileDecay(model); // ~24

// Get time to 90% confidence  
const highConfidence = ebisu.modelToPercentileDecay(model, 0.9); // ~3.4

// Get time to 10% confidence
const lowConfidence = ebisu.modelToPercentileDecay(model, 0.1); // ~99.3

// Use custom tolerance for higher precision
const precise = ebisu.modelToPercentileDecay(model, 0.5, 1e-6);

Halflife Adjustment

Rescales a model's halflife by a multiplicative factor while preserving the probability distribution shape.

/**
 * Rescales model's halflife by multiplicative factor
 * @param prior - Current memory model tuple [alpha, beta, time]
 * @param scale - Scaling factor for halflife (default: 1)
 * @returns New memory model with scaled halflife
 */
function rescaleHalflife(prior: Model, scale?: number): Model;

Usage Examples:

const model = ebisu.defaultModel(24);

// Make fact review twice as often (halve the halflife)
const moreFrequent = ebisu.rescaleHalflife(model, 0.5);

// Make fact review less often (10x the halflife)
const lessFrequent = ebisu.rescaleHalflife(model, 10);

// Check the results
ebisu.modelToPercentileDecay(moreFrequent); // ~12 hours
ebisu.modelToPercentileDecay(lessFrequent); // ~240 hours

Mathematical Customization

Allows customization of internal mathematical functions for advanced use cases.

/**
 * Allows customization of mathematical functions for advanced use cases
 * @param args - Object with optional betaln and/or betafn function replacements
 * @returns Object containing original functions for restoration
 */
function customizeMath(args: {
  betaln?: (a: number, b: number) => number;
  betafn?: (a: number, b: number) => number;
}): {
  betaln: (a: number, b: number) => number;
  betafn: (a: number, b: number) => number;
};

Usage Example:

// Replace mathematical functions (advanced usage)
const original = ebisu.customizeMath({
  betaln: (a, b) => customLogBetaFunction(a, b),
  betafn: (a, b) => customBetaFunction(a, b)
});

// Perform operations with custom math...

// Restore original functions
ebisu.customizeMath(original);

Types

/**
 * Memory model tuple representing [alpha, beta, time]
 * - alpha: Alpha parameter of Beta distribution
 * - beta: Beta parameter of Beta distribution  
 * - time: Time associated with the distribution
 */
type Model = [number, number, number];

/**
 * Configuration options for numerical optimization in updateRecall
 */
interface MinimizeParams {
  /** Numerical tolerance for optimization convergence */
  tolerance: number;
  /** Whether to use logarithmic calculations for numerical stability */
  useLog: boolean;
}

Error Handling

Ebisu-js includes robust error handling for common edge cases:

  • Invalid parameters: Functions validate input ranges and throw descriptive errors
  • Numerical instability: Automatic fallback to log-domain calculations when needed
  • Convergence failures: Clear error messages when optimization fails to converge
  • Mathematical edge cases: Graceful handling of extreme parameter values
// Example error cases
try {
  ebisu.updateRecall(model, -1, 1, 10); // Error: successes must be >= 0
  ebisu.updateRecall(model, 2, 1, 10);  // Error: successes must be <= total
} catch (error) {
  console.error("Invalid quiz parameters:", error.message);
}