跳转至

正则化线性模型:首选模型

1. 核心目标

指标的有效性远比使用指标生成交易信号的预测模型复杂度更重要

开发新交易系统时,优先使用线性模型;仅当线性模型存在明确局限(如无法捕捉指标间强非线性交互)时,才考虑进阶到非线性模型

针对交易系统中“用线性模型预测市场收益/趋势”的场景(如基于技术指标预测次日涨跌),通过正则化约束平衡模型拟合能力与泛化能力,避免因模型复杂度过高导致“学习噪声而非真实市场模式”

2. 核心原理

(1)正则化类型:岭回归+Lasso+弹性网(正则化思想)

  • 通过参数alpha控制正则化类型:
  • alpha=0:岭回归(L2正则化),惩罚系数平方和($ \lambda\sum\beta_j^2 $),使高相关指标系数趋于平均,避免系数极端值,适用于指标间存在相关性的场景(如多个趋势类指标);
  • alpha=1:Lasso(L1正则化),惩罚系数绝对值和($ \lambda\sum|\beta_j| $),会使部分无关指标系数归零(变量选择),适用于筛选核心指标;
  • 0<alpha<1:弹性网(推荐),同时结合L1和L2惩罚,兼顾“变量选择”与“抑制系数极端值”,适配多数交易场景。
  • lambda控制正则化强度:值越大,对系数的约束越强,模型越简单(泛化能力越强,但拟合能力可能下降)。

(2)训练算法:坐标下降法(保证收敛性)

  • 核心逻辑:逐变量更新系数,每次固定其他变量,仅优化当前变量,通过“活跃集迭代”(仅处理非零系数)提升效率,符号“快速训练线性模型”的需求;
  • 关键步骤:

  • 数据标准化:对输入指标(如趋势、波动率)和目标变量(如收益)做“减均值、除标准差”处理(书中要求,减少数值误差,提升收敛速度);

  • 协方差快速更新:当样本数(市场历史bar数)远大于指标数时,预计算指标间协方差矩阵、指标与目标的交叉协方差,将每次迭代的时间复杂度从$ O(N*K) \((N为样本数,K为指标数)降至\) O(K^2) $,适配交易系统“大样本、多指标”的高效计算需求;
  • 软阈值更新:Lasso/L1正则化的核心操作,对优化后的系数施加“阈值裁剪”,使小系数归零(实现变量选择),公式为: $ S(z,\gamma)=\begin{cases}z-\gamma &amp; z&gt;\gamma \ z+\gamma &amp; z&lt;-\gamma \ 0 &amp; \text{otherwise}\end{cases} $ 其中$ \gamma=\alpha*\lambda $(正则化强度与类型的结合项)。

(3)Lambda优化:路径下降+交叉验证(“最优正则化强度选择”)

  • Lambda路径下降:从“使所有系数归零的大Lambda”开始,逐步减小Lambda(按指数衰减),每次用前一Lambda的系数作为初始值(暖启动),大幅减少迭代次数(高效寻优策略);
  • 交叉验证(CV):将数据划分为多折(如5折),每折用部分数据训练、剩余数据验证,选择“验证集解释方差最大”的Lambda,确保正则化强度适配真实市场泛化需求(避免“过拟合正则化参数”的关键手段)。

(4)预测逻辑

将输入的原始指标标准化后代入线性模型($ \hat{y}=\beta_0+\sum\beta_jx_j $),再将预测结果还原为原始尺度(乘目标标准差+加目标均值),确保输出符合实际市场收益/趋势的数值范围。

#include <cmath>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <vector>

// 错误码定义
enum class CoordinateDescentErr {
  SUCCESS = 0,
  INVALID_PARAM = 1,      // α∈[0,1]、λ≥0等参数非法
  INSUFFICIENT_DATA = 2,  // 样本数<特征数
  MEMORY_FAILED = 3       // 内存分配失败
};

class CoordinateDescent {
 public:
  /**
   * @brief 构造函数:初始化正则化线性模型
   * @param n_vars 特征数(预测变量数)
   * @param n_cases 样本数
   * @param use_weights 是否使用样本权重
   * @param use_covar_updates 是否启用快速协方差更新(样本数远大于特征数时推荐)
   * @param n_lambdas lambda路径搜索的点数
   */
  CoordinateDescent(int n_vars, int n_cases, bool use_weights,
                    bool use_covar_updates, int n_lambdas)
      : n_vars_(n_vars),
        n_cases_(n_cases),
        use_weights_(use_weights),
        use_covar_updates_(use_covar_updates),
        n_lambdas_(n_lambdas),
        beta_(nullptr),
        residuals_(nullptr),
        X_inner_(nullptr),
        Y_inner_(nullptr),
        XSS_vec_(nullptr),
        weights_(nullptr),
        lambdas_(nullptr),
        lambda_beta_(nullptr) {
    // 参数检查
    if (n_vars_ <= 0 || n_cases_ <= 0 || n_lambdas_ < 0) {
      error_code_ = CoordinateDescentErr::INVALID_PARAM;
      return;
    }

    // 样本数检查
    if (n_cases_ < n_vars_) {
      error_code_ = CoordinateDescentErr::INSUFFICIENT_DATA;
      return;
    }

    // 内存分配
    beta_ = new (std::nothrow) double[n_vars_]{};
    residuals_ = new (std::nothrow) double[n_cases_]{};
    if (use_covar_updates_) {
      X_inner_ = new (std::nothrow) double[n_vars_ * n_vars_]{};
      Y_inner_ = new (std::nothrow) double[n_vars_]{};
    }
    if (use_weights_) {
      XSS_vec_ = new (std::nothrow) double[n_vars_]{};
      weights_ = new (std::nothrow) double[n_cases_]{};
    }
    if (n_lambdas_ > 0) {
      lambdas_ = new (std::nothrow) double[n_lambdas_]{};
      lambda_beta_ = new (std::nothrow) double[n_lambdas_ * n_vars_]{};
    }

    // 内存检查
    if (!beta_ || !residuals_ ||
        (use_covar_updates_ && (!X_inner_ || !Y_inner_)) ||
        (use_weights_ && (!XSS_vec_ || !weights_)) ||
        (n_lambdas_ > 0 && (!lambdas_ || !lambda_beta_))) {
      // 清理已分配的内存
      cleanup();
      error_code_ = CoordinateDescentErr::MEMORY_FAILED;
      return;
    }

    error_code_ = CoordinateDescentErr::SUCCESS;
  }

  ~CoordinateDescent() { cleanup(); }

  /**
   * @brief 输入训练数据并标准化
   * @param start_idx 数据起始索引(支持数据循环使用)
   * @param total_cases 总样本数(用于循环)
   * @param X 特征矩阵(n_cases × n_vars)
   * @param Y 目标变量(n_cases × 1)
   * @param weights 样本权重(n_cases × 1,nullptr表示等权重)
   * @return CoordinateDescentErr 错误码
   */
  CoordinateDescentErr load_data(int start_idx, int total_cases,
                                 const double* X, const double* Y,
                                 const double* weights) {
    if (n_cases_ <= 0 || n_vars_ <= 0)
      return CoordinateDescentErr::INVALID_PARAM;
    if (!X || !Y) return CoordinateDescentErr::INVALID_PARAM;
    if (start_idx < 0 || total_cases <= 0)
      return CoordinateDescentErr::INVALID_PARAM;

    // 1. 复制并标准化样本权重(权重求和为1)
    if (use_weights_) {
      if (!weights) return CoordinateDescentErr::INVALID_PARAM;
      double sum_w = 0.0;
      for (int i = 0; i < n_cases_; ++i) {
        int idx = (start_idx + i) % total_cases;
        weights_[i] = weights[idx];
        sum_w += weights_[i];
      }
      if (sum_w < 1e-10)
        return CoordinateDescentErr::INVALID_PARAM;  // 权重不能全为0
      for (int i = 0; i < n_cases_; ++i) weights_[i] /= sum_w;
    }

    // 2. 标准化特征与目标变量(零均值、单位方差)
    std::vector<double> X_mean(n_vars_, 0.0), X_std(n_vars_, 0.0);
    double Y_mean = 0.0, Y_std = 0.0;

    // 计算均值
    for (int i = 0; i < n_cases_; ++i) {
      int idx = (start_idx + i) % total_cases;
      const double* x = X + idx * n_vars_;
      double y = Y[idx];
      Y_mean += use_weights_ ? weights_[i] * y : y;
      for (int j = 0; j < n_vars_; ++j) {
        X_mean[j] += use_weights_ ? weights_[i] * x[j] : x[j];
      }
    }
    if (!use_weights_) {
      Y_mean /= n_cases_;
      for (int j = 0; j < n_vars_; ++j) {
        X_mean[j] /= n_cases_;
      }
    }

    // 计算标准差
    for (int i = 0; i < n_cases_; ++i) {
      int idx = (start_idx + i) % total_cases;
      const double* x = X + idx * n_vars_;
      double y = Y[idx] - Y_mean;
      Y_std += use_weights_ ? weights_[i] * y * y : y * y;
      for (int j = 0; j < n_vars_; ++j) {
        double x_norm = x[j] - X_mean[j];
        X_std[j] +=
            use_weights_ ? weights_[i] * x_norm * x_norm : x_norm * x_norm;
      }
    }
    if (!use_weights_) {
      Y_std /= n_cases_;
      for (int j = 0; j < n_vars_; ++j) {
        X_std[j] /= n_cases_;
      }
    }

    // 避免标准差为0
    Y_std = std::sqrt(Y_std + 1e-60);
    for (int j = 0; j < n_vars_; ++j) {
      X_std[j] = std::sqrt(X_std[j] + 1e-60);
    }

    // 保存标准化参数用于后续预测
    X_mean_ = X_mean;
    X_std_ = X_std;
    Y_mean_ = Y_mean;
    Y_std_ = Y_std;

    // 3. 计算协方差矩阵
    if (use_covar_updates_) {
      memset(X_inner_, 0, n_vars_ * n_vars_ * sizeof(double));
      memset(Y_inner_, 0, n_vars_ * sizeof(double));

      for (int j = 0; j < n_vars_; ++j) {
        // 计算特征与目标的协方差
        double sum_y = 0.0;
        for (int i = 0; i < n_cases_; ++i) {
          int idx = (start_idx + i) % total_cases;
          const double* x = X + idx * n_vars_;
          double x_norm = (x[j] - X_mean[j]) / X_std[j];
          double y_norm = (Y[idx] - Y_mean) / Y_std;
          sum_y +=
              use_weights_ ? weights_[i] * x_norm * y_norm : x_norm * y_norm;
        }
        Y_inner_[j] = sum_y;

        // 计算特征间的协方差(对称矩阵)
        for (int k = j; k < n_vars_; ++k) {
          double sum_x = 0.0;
          for (int i = 0; i < n_cases_; ++i) {
            int idx = (start_idx + i) % total_cases;
            const double* x = X + idx * n_vars_;
            double xj_norm = (x[j] - X_mean[j]) / X_std[j];
            double xk_norm = (x[k] - X_mean[k]) / X_std[k];
            sum_x += use_weights_ ? weights_[i] * xj_norm * xk_norm
                                  : xj_norm * xk_norm;
          }
          X_inner_[j * n_vars_ + k] = sum_x;
          X_inner_[k * n_vars_ + j] = sum_x;
        }

        // 计算特征平方的期望
        if (use_weights_) {
          double sum_x2 = 0.0;
          for (int i = 0; i < n_cases_; ++i) {
            int idx = (start_idx + i) % total_cases;
            const double* x = X + idx * n_vars_;
            double x_norm = (x[j] - X_mean[j]) / X_std[j];
            sum_x2 += weights_[i] * x_norm * x_norm;
          }
          XSS_vec_[j] = sum_x2;
        } else {
          XSS_vec_[j] = 1.0;  // 标准化后特征平方期望为1
        }
      }
    }

    // 4. 初始化残差(初始为标准化后的目标变量)
    for (int i = 0; i < n_cases_; ++i) {
      int idx = (start_idx + i) % total_cases;
      residuals_[i] = (Y[idx] - Y_mean) / Y_std;
    }
    memset(beta_, 0, n_vars_ * sizeof(double));  // 初始系数为0
    return CoordinateDescentErr::SUCCESS;
  }

  /**
   * @brief 核心训练:坐标下降优化模型系数
   * @param alpha 正则化类型(0=Ridge,1=Lasso,0<α<1=混合)
   * @param lambda 正则化强度(≥0)
   * @param max_iter 最大迭代次数(防止死循环)
   * @param eps 收敛阈值(系数变化量<eps则收敛)
   * @param fast_test 是否使用快速收敛测试(基于系数变化量)
   * @param warm_start 是否从当前系数继续训练
   * @return CoordinateDescentErr 错误码
   */
  CoordinateDescentErr core_train(double alpha, double lambda, int max_iter,
                                  double eps, bool fast_test, bool warm_start) {
    // 参数合法性检查
    if (alpha < 0 || alpha > 1 || lambda < 0 || max_iter <= 0 || eps <= 0) {
      return CoordinateDescentErr::INVALID_PARAM;
    }

    // warm_start=false时残差已在load_data中初始化(=标准化目标变量)
    if (warm_start && !use_covar_updates_) {
      // 重新计算残差:residuals = 标准化目标变量 - 特征×系数
      memset(residuals_, 0, n_cases_ * sizeof(double));
      for (int i = 0; i < n_cases_; ++i) {
        // 计算标准化目标变量值
        double y_std = (Y_[i] - Y_mean_) / Y_std_;  // Y_是原始目标变量数组
        residuals_[i] = y_std;

        // 减去特征×系数的累加值
        for (int j = 0; j < n_vars_; ++j) {
          // 计算标准化特征值
          double x_std = (X_[i * n_vars_ + j] - X_mean_[j]) /
                         X_std_[j];  // X_是原始特征矩阵
          residuals_[i] -= x_std * beta_[j];
        }
      }
    }

    const double S_threshold = alpha * lambda;  // 软阈值
    bool do_active_only = false;                // 是否只优化非零系数
    double prior_crit = 1e60;                   // 前一次迭代的目标函数值

    for (int iter = 0; iter < max_iter; ++iter) {
      bool active_set_changed = false;
      double max_beta_change = 0.0;

      // 遍历所有特征,更新系数
      for (int j = 0; j < n_vars_; ++j) {
        // 跳过零系数(活跃集优化)
        if (do_active_only && std::fabs(beta_[j]) < 1e-10) continue;

        // 1. 计算更新分母:XSS[j] + lambda*(1-α)
        double XSS = use_weights_ ? XSS_vec_[j] : 1.0;
        double update_factor = XSS + lambda * (1.0 - alpha);
        if (update_factor < 1e-10) update_factor = 1e-10;  // 防止除以零

        // 2. 计算参数更新的输入值(argument)
        double argument = 0.0;
        if (use_covar_updates_) {
          // 快速协方差更新:argument = 特征目标协方差 - 特征系数协方差和 +
          // XSS×当前系数
          double sum_xb = 0.0;
          for (int k = 0; k < n_vars_; ++k) {
            sum_xb += X_inner_[j * n_vars_ + k] * beta_[k];
          }
          argument = Y_inner_[j] - sum_xb + XSS * beta_[j];
        } else {
          // 朴素更新:argument = 特征残差协方差 + 当前系数
          double sum_xr = 0.0;
          for (int i = 0; i < n_cases_; ++i) {
            // 计算标准化特征值
            int idx = i;          // 这里需要根据实际数据索引计算
            double x_norm = 0.0;  // 需要根据实际特征值计算
            // 假设这里可以访问原始数据来计算标准化特征值
            sum_xr += use_weights_ ? weights_[i] * x_norm * residuals_[i]
                                   : x_norm * residuals_[i];
          }
          sum_xr /= use_weights_ ? 1.0 : n_cases_;
          argument = sum_xr + beta_[j];
        }

        // 3. 软阈值操作:根据argument更新系数
        double new_beta = 0.0;
        if (argument > 0 && S_threshold < argument) {
          new_beta = (argument - S_threshold) / update_factor;
        } else if (argument < 0 && S_threshold < -argument) {
          new_beta = (argument + S_threshold) / update_factor;
        } else {
          new_beta = 0.0;
        }

        // 4. 更新残差(仅朴素更新需要)
        double beta_change = new_beta - beta_[j];
        if (!use_covar_updates_ && std::fabs(beta_change) > 1e-10) {
          for (int i = 0; i < n_cases_; ++i) {
            // 计算标准化特征值
            double x_norm = 0.0;  // 需要根据实际特征值计算
            residuals_[i] -= beta_change * x_norm;
          }
        }

        // 5. 记录最大变化量与活跃集变更
        max_beta_change = std::max(max_beta_change, std::fabs(beta_change));
        if ((beta_[j] == 0 && new_beta != 0) ||
            (beta_[j] != 0 && new_beta == 0)) {
          active_set_changed = true;
        }

        // 6. 更新系数
        beta_[j] = new_beta;
      }

      // 收敛测试
      bool converged = false;
      if (fast_test) {
        converged = (max_beta_change < eps);
      } else {
        // 计算目标函数值:均方误差 + 2×lambda×正则化惩罚项
        double mse = 0.0;
        for (int i = 0; i < n_cases_; ++i) {
          mse += use_weights_ ? weights_[i] * residuals_[i] * residuals_[i]
                              : residuals_[i] * residuals_[i];
        }
        mse /= use_weights_ ? 1.0 : n_cases_;

        double penalty = 0.0;
        for (int j = 0; j < n_vars_; ++j) {
          penalty += 0.5 * (1.0 - alpha) * beta_[j] * beta_[j] +
                     alpha * std::fabs(beta_[j]);
        }
        penalty *= 2 * lambda;

        double current_crit = mse + penalty;
        converged = (prior_crit - current_crit < eps);
        prior_crit = current_crit;
      }

      // 活跃集逻辑:收敛后全量检查,否则仅优化活跃集
      if (do_active_only) {
        do_active_only = !converged;
      } else {
        do_active_only = converged && !active_set_changed;
        if (converged && !active_set_changed) break;
      }
    }

    return CoordinateDescentErr::SUCCESS;
  }

  /**
   * @brief Lambda路径搜索:逐步减小lambda并训练,获取不同正则化强度下的系数
   * @param alpha 正则化类型
   * @param max_iter 每一步lambda的最大迭代次数
   * @param eps 收敛阈值
   * @param fast_test 快速收敛测试
   * @param max_lambda 初始lambda(负表示自动计算)
   * @param print_steps 是否打印路径结果
   * @return CoordinateDescentErr 错误码
   */
  CoordinateDescentErr lambda_train(double alpha, int max_iter, double eps,
                                    bool fast_test, double max_lambda,
                                    bool print_steps) {
    if (n_lambdas_ <= 1) return CoordinateDescentErr::INVALID_PARAM;

    // 1. 计算初始lambda:使所有系数为零的最小lambda
    if (max_lambda <= 0) {
      double lambda_thresh = 0.0;
      for (int j = 0; j < n_vars_; ++j) {
        double sum_xy = use_weights_ ? Y_inner_[j] : (Y_inner_[j] * n_cases_);
        double thresh_j = std::fabs(sum_xy) / (alpha + 1e-60);
        lambda_thresh = std::max(lambda_thresh, thresh_j);
      }
      max_lambda = 0.999 * lambda_thresh;  // 略小于阈值,确保初始有非零系数
    }
    double min_lambda = 0.001 * max_lambda;  // 最小lambda
    double lambda_factor = std::exp(std::log(min_lambda / max_lambda) /
                                    (n_lambdas_ - 1));  // 指数衰减

    // 2. 遍历lambda路径,逐步减小lambda并训练
    double current_lambda = max_lambda;
    for (int l = 0; l < n_lambdas_; ++l) {
      lambdas_[l] = current_lambda;

      // warm_start训练:从上次lambda的系数继续
      core_train(alpha, current_lambda, max_iter, eps, fast_test, (l > 0));

      // 保存当前lambda的系数
      memcpy(lambda_beta_ + l * n_vars_, beta_, n_vars_ * sizeof(double));

      // 打印结果(可选)
      if (print_steps) {
        int n_active = 0;
        for (int j = 0; j < n_vars_; ++j) {
          if (std::fabs(beta_[j]) > 1e-10) n_active++;
        }
        // 可添加解释方差打印逻辑
      }

      current_lambda *= lambda_factor;
    }

    return CoordinateDescentErr::SUCCESS;
  }

  // 获取训练结果
  const double* get_beta() const { return beta_; }
  const double* get_lambdas() const { return lambdas_; }
  const double* get_lambda_beta() const { return lambda_beta_; }

  // 获取错误码
  CoordinateDescentErr get_error_code() const { return error_code_; }

 private:
  // 资源清理函数
  void cleanup() {
    delete[] beta_;
    delete[] residuals_;
    delete[] X_inner_;
    delete[] Y_inner_;
    delete[] XSS_vec_;
    delete[] weights_;
    delete[] lambdas_;
    delete[] lambda_beta_;
  }

 private:
  int n_vars_;              // 特征数
  int n_cases_;             // 样本数
  bool use_weights_;        // 是否使用样本权重
  bool use_covar_updates_;  // 是否启用快速协方差更新
  int n_lambdas_;           // lambda路径搜索点数

  double* beta_;         // 模型系数(n_vars_)
  double* residuals_;    // 残差(n_cases_)
  double* X_inner_;      // 特征协方差矩阵(n_vars_×n_vars_)
  double* Y_inner_;      // 特征与目标协方差(n_vars_)
  double* XSS_vec_;      // 特征平方期望(n_vars_)
  double* weights_;      // 样本权重(n_cases_)
  double* lambdas_;      // 路径中的lambda值(n_lambdas_)
  double* lambda_beta_;  // 各lambda对应的系数(n_lambdas_×n_vars_)

  // 添加原始数据存储
  double* X_;  // 原始特征数据(n_cases_ × n_vars_)
  double* Y_;  // 原始目标变量(n_cases_)

  // 标准化参数
  std::vector<double> X_mean_;
  std::vector<double> X_std_;
  double Y_mean_;
  double Y_std_;

  // 错误码
  CoordinateDescentErr error_code_;
};
#include "CoordinateDescent.h"

void test_coordinate_descent() {
  std::cout << "Testing Coordinate Descent Implementation\n";
  std::cout << "========================================\n";

  // 创建测试数据
  const int n_vars = 5;
  const int n_cases = 100;

  // 生成测试数据
  std::vector<double> X(n_cases * n_vars);
  std::vector<double> Y(n_cases);
  std::vector<double> weights(n_cases, 1.0);  // 等权重

  // 填充特征数据 (随机数据)
  for (int i = 0; i < n_cases; ++i) {
    for (int j = 0; j < n_vars; ++j) {
      X[i * n_vars + j] = (double)rand() / RAND_MAX;
    }
  }

  // 生成目标变量 (线性组合加噪声)
  for (int i = 0; i < n_cases; ++i) {
    Y[i] = 0.0;
    for (int j = 0; j < n_vars; ++j) {
      Y[i] += (j + 1) * X[i * n_vars + j];
    }
    Y[i] += 0.1 * ((double)rand() / RAND_MAX - 0.5);  // 添加噪声
  }

  // 测试1: 基本功能测试
  std::cout << "Test 1: Basic functionality test\n";
  CoordinateDescent cd1(n_vars, n_cases, false, false, 0);
  if (cd1.get_error_code() != CoordinateDescentErr::SUCCESS) {
    std::cout << " Failed to create CoordinateDescent object\n";
    return;
  }

  CoordinateDescentErr err =
      cd1.load_data(0, n_cases, X.data(), Y.data(), nullptr);
  if (err != CoordinateDescentErr::SUCCESS) {
    std::cout << " Failed to load data\n";
    return;
  }

  err = cd1.core_train(0.5, 0.1, 100, 1e-6, false, false);
  if (err != CoordinateDescentErr::SUCCESS) {
    std::cout << " Failed to train model\n";
    return;
  }

  std::cout << " Coefficients: ";
  const double* beta = cd1.get_beta();
  for (int j = 0; j < n_vars; ++j) {
    std::cout << std::fixed << std::setprecision(4) << beta[j] << " ";
  }
  std::cout << "\n";

  // 测试2: 带权重功能测试
  std::cout << "Test 2: Weighted functionality test\n";
  CoordinateDescent cd2(n_vars, n_cases, true, false, 0);
  if (cd2.get_error_code() != CoordinateDescentErr::SUCCESS) {
    std::cout << " Failed to create weighted CoordinateDescent object\n";
    return;
  }

  err = cd2.load_data(0, n_cases, X.data(), Y.data(), weights.data());
  if (err != CoordinateDescentErr::SUCCESS) {
    std::cout << " Failed to load weighted data\n";
    return;
  }

  err = cd2.core_train(1.0, 0.1, 100, 1e-6, true, false);
  if (err != CoordinateDescentErr::SUCCESS) {
    std::cout << " Failed to train weighted model\n";
    return;
  }

  std::cout << " Coefficients: ";
  beta = cd2.get_beta();
  for (int j = 0; j < n_vars; ++j) {
    std::cout << std::fixed << std::setprecision(4) << beta[j] << " ";
  }
  std::cout << "\n";

  // 测试3: Lambda路径搜索测试
  std::cout << "Test 3: Lambda path search test\n";
  CoordinateDescent cd3(n_vars, n_cases, false, true, 10);
  if (cd3.get_error_code() != CoordinateDescentErr::SUCCESS) {
    std::cout << " Failed to create path search CoordinateDescent object\n";
    return;
  }

  err = cd3.load_data(0, n_cases, X.data(), Y.data(), nullptr);
  if (err != CoordinateDescentErr::SUCCESS) {
    std::cout << " Failed to load data for path search\n";
    return;
  }

  err = cd3.lambda_train(0.8, 50, 1e-4, true, -1.0, false);
  if (err != CoordinateDescentErr::SUCCESS) {
    std::cout << " Failed to perform lambda path search\n";
    return;
  }

  std::cout << " Lambda path search completed successfully\n";

  // 测试4: 错误处理测试
  std::cout << "Test 4: Error handling test\n";
  CoordinateDescent cd4(-1, n_cases, false, false, 0);
  if (cd4.get_error_code() == CoordinateDescentErr::INVALID_PARAM) {
    std::cout << " Correctly handled invalid parameter\n";
  } else {
    std::cout << " Failed to handle invalid parameter\n";
  }

  CoordinateDescent cd5(n_vars, n_vars - 1, false, false, 0);
  if (cd5.get_error_code() == CoordinateDescentErr::INSUFFICIENT_DATA) {
    std::cout << " Correctly handled insufficient data\n";
  } else {
    std::cout << " Failed to handle insufficient data\n";
  }

  std::cout << "All tests completed.\n";
}

int main() {
  test_coordinate_descent();
  return 0;
}