adf function

ADFResult adf(
  1. List<double> x, {
  2. int? maxLags,
})

Implementation

ADFResult adf(List<double> x, {int? maxLags}) {
  final n=x.length; if (n<12) return ADFResult(double.nan,0);
  final d = List<double>.generate(n-1,(i)=> x[i+1]-x[i]);
  final y1= x.sublist(0,n-1), y = x.sublist(1);
  final k = maxLags ?? math.max(0,(math.pow(n/100.0,0.25)).floor());
  final rows = y.length - k;
  if (rows<=3) return ADFResult(double.nan,k);

  // X = [const, y_{t-1}, d_{t-1}..d_{t-k}]
  final X = List.generate(rows, (_)=> <double>[]);
  final Y = List<double>.filled(rows, 0.0);
  for (int t=k; t<y.length; t++){
    final row=<double>[1.0, y1[t]];
    for (int i=1;i<=k;i++) row.add(d[t-i]);
    X[t-k]=row; Y[t-k]=y[t];
  }

  List<double> solve(List<List<double>> A, List<double> b) {
    final n=A.length, m=A[0].length;
    final M=List.generate(n,(i)=>List<double>.from(A[i]));
    final y=List<double>.from(b);
    // normal eq: (X'X) beta = X'Y
    // build XtX, XtY
    final XtX=List.generate(m,(_)=>List<double>.filled(m,0.0));
    final XtY=List<double>.filled(m,0.0);
    for (int i=0;i<n;i++){
      for (int a=0;a<m;a++){
        XtY[a]+=M[i][a]*y[i];
        for (int b=0;b<m;b++) XtX[a][b]+=M[i][a]*M[i][b];
      }
    }
    // Gauss elim.
    final A2=List.generate(m,(i)=>List<double>.from(XtX[i]));
    final b2=List<double>.from(XtY);
    for (int i=0;i<m;i++){
      int piv=i; double mx=A2[i][i].abs();
      for (int r=i+1;r<m;r++){ final v=A2[r][i].abs(); if (v>mx){mx=v; piv=r;} }
      if (piv!=i){ final t=A2[i]; A2[i]=A2[piv]; A2[piv]=t; final tb=b2[i]; b2[i]=b2[piv]; b2[piv]=tb; }
      final d=A2[i][i]; for (int c=i;c<m;c++) A2[i][c]/=d; b2[i]/=d;
      for (int r=0;r<m;r++){ if (r==i) continue; final f=A2[r][i];
        for (int c=i;c<m;c++) A2[r][c]-=f*A2[i][c]; b2[r]-=f*b2[i]; }
    }
    return b2;
  }

  final beta = solve(X, Y);  // [c, alpha, phi...]
  // residual var & se(alpha)
  final m=X[0].length;
  final yhat=List<double>.generate(rows,(i){ var s=0.0; for (int j=0;j<m;j++) s+=X[i][j]*beta[j]; return s;});
  var sse=0.0; for (int i=0;i<rows;i++) sse+=(Y[i]-yhat[i])*(Y[i]-yhat[i]);
  final sigma2=sse/(rows-m);
  // (X'X)^{-1}
  final XtX=List.generate(m,(_)=>List<double>.filled(m,0.0));
  for (int i=0;i<rows;i++) for (int a=0;a<m;a++) for (int b=0;b<m;b++) XtX[a][b]+=X[i][a]*X[i][b];
  final inv = (){
    final A=List.generate(m,(i)=>List<double>.from(XtX[i]));
    final I=List.generate(m,(i)=>List<double>.filled(m,0.0)); for (int i=0;i<m;i++) I[i][i]=1.0;
    for (int i=0;i<m;i++){
      int piv=i; double mx=A[i][i].abs(); for (int r=i+1;r<m;r++){ final v=A[r][i].abs(); if (v>mx){mx=v; piv=r;} }
      final t=A[i]; A[i]=A[piv]; A[piv]=t; final ti=I[i]; I[i]=I[piv]; I[piv]=ti;
      final d=A[i][i]; for (int c=0;c<m;c++){ A[i][c]/=d; I[i][c]/=d; }
      for (int r=0;r<m;r++){ if (r==i) continue; final f=A[r][i]; for (int c=0;c<m;c++){ A[r][c]-=f*A[i][c]; I[r][c]-=f*I[i][c]; } }
    }
    return I;
  }();
  final seAlpha = math.sqrt(sigma2 * inv[1][1]);
  final tau = beta[1] / (seAlpha==0?1e-12:seAlpha);
  return ADFResult(tau, k);
}