adf function
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);
}