estimateHalfLife static method

double? estimateHalfLife(
  1. List<RetentionBucket> buckets
)

Estimate the half-life of memory (in days) from retention data.

Uses a simple exponential decay fit: R(t) = 2^(-t/halfLife). Returns null if insufficient data.

Implementation

static double? estimateHalfLife(List<RetentionBucket> buckets) {
  if (buckets.length < 2) return null;

  // Weighted least-squares on log-transform: ln(R) = -(ln2/H) * t
  // → slope = -ln2/H → H = -ln2/slope
  var sumWT = 0.0;
  var sumWLnR = 0.0;
  var sumWT2 = 0.0;
  var sumWTLnR = 0.0;
  var sumW = 0.0;

  for (final b in buckets) {
    if (b.retentionRate <= 0 || b.retentionRate >= 1) continue;
    final t = b.intervalDays.toDouble();
    final lnR = math.log(b.retentionRate);
    final w = b.totalReviews.toDouble(); // weight by sample size
    sumW += w;
    sumWT += w * t;
    sumWLnR += w * lnR;
    sumWT2 += w * t * t;
    sumWTLnR += w * t * lnR;
  }

  if (sumW == 0) return null;
  final slope =
      (sumW * sumWTLnR - sumWT * sumWLnR) / (sumW * sumWT2 - sumWT * sumWT);
  if (slope >= 0) return null; // retention can't increase with time

  return -math.ln2 / slope;
}