1// Robust covariance estimators for linear regression (CPU FP64 reference).2// Conventions follow statsmodels 0.15 (HC0–HC3, HAC Bartlett/Newey–West with use_correction=False) and3// Cameron–Gelbach–Miller one-way cluster with the Stata-style correction G/(G−1)·(N−1)/(N−K).4#pragma once5#include <vector>6#include <span>7#include <string>8#include <Eigen/Dense>9#include "raid/core/types.hpp"1011namespace raid::stats {1213enum class CovType { classical, hc0, hc1, hc2, hc3, hac_bartlett, cluster };14std::string to_string(CovType c);15CovType covtype_from_string(std::string_view s);1617struct CovOptions {18 CovType type{CovType::classical};19 int hac_lags{-1}; // −1 → floor(4 (n/100)^{2/9}) (Newey–West 1994 rule of thumb used by statsmodels users; documented)20 bool hac_small_sample{false}; // n/(n−k) factor (statsmodels use_correction)21 std::span<const i64> clusters{}; // cluster id per observation (CovType::cluster)22 bool cluster_small_sample{true}; // G/(G−1)·(N−1)/(N−K)23};2425/// Covariance of OLS/WLS coefficients given X (n×k), residuals e (n), and (X'X)^{-1} computed stably by the caller.26/// `leverage` (h_ii) is required for HC2/HC3 and may be empty otherwise.27Eigen::MatrixXd robust_covariance(const Eigen::Ref<const Eigen::MatrixXd>& X, const Eigen::Ref<const Eigen::VectorXd>& resid,28 const Eigen::Ref<const Eigen::MatrixXd>& xtx_inv, const CovOptions& opt,29 const Eigen::VectorXd& leverage = Eigen::VectorXd());30int default_hac_lags(usize n);3132} // namespace raid::stats33