diff --git a/GCTL_logo.jpg b/GCTL_logo.jpg new file mode 100644 index 0000000..80cc016 Binary files /dev/null and b/GCTL_logo.jpg differ diff --git a/README.md b/README.md index eaecad9..581999e 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,391 @@ -## lcg_solver 共轭梯度求解器 -### 求解器参数设置 -#### 1. 从toml文件读取参数 +![logo](GCTL_logo.jpg) -用户可以从toml文件中读取并设置求解器参数。所有的参数都定义在名为lcg的顶级表格下,可设置的参数及类型如下所示: +# GCTL Optimization Library + +> **注意**: 本文档由 Cursor AI 自动生成。文档中的函数名称、参数和用法说明可能存在错误,请以头文件(`.h`)中的实际函数声明为准。如发现任何不一致,请以源代码为准。 + +GCTL Optimization Library 是一个高效的数值优化算法库,提供了多种优化算法实现和求解器。该库是 Generic Scientific Template Library (GSTL) 的一部分。 + +## 主要特性 + +- 多种优化算法实现 + - LCG (Linear Conjugate Gradient): 线性共轭梯度法 + - CLCG (Complex Linear Conjugate Gradient): 复数域线性共轭梯度法 + - L-BFGS (Limited-memory BFGS): 限制内存BFGS算法 + - SGD (Stochastic Gradient Descent): 随机梯度下降 + - LGD (Lévy Gradient Descent): 基于Lévy飞行的随机搜索方法,具有全局收敛性 + - SVD (Singular Value Decomposition): 奇异值分解 + +- 矩阵分解工具 + - Cholesky分解 + - LU分解 + - SVD分解 + +- 损失函数支持 + - 提供多种常用损失函数 + - 支持自定义损失函数 + +## 安装 + +项目使用CMake构建系统。安装步骤如下: + +```bash +mkdir build +cd build +cmake .. +make +``` + +## 使用方法 + +### 1. 配置求解器 + +所有求解器都支持通过TOML配置文件设置参数: ```toml -[lcg] -max_iterations= -epsilon= -abs_diff=0|1 -restart_epsilon= -step= -sigma= -beta= -maxi_m= -``` \ No newline at end of file +[solver] +max_iterations=1000 # 最大迭代次数 +epsilon=1e-6 # 收敛阈值 +abs_diff=1 # 是否使用绝对差异 +restart_epsilon=1e-4 # 重启阈值 +step=0.1 # 步长 +sigma=0.9 # sigma参数 +beta=0.1 # beta参数 +maxi_m=10 # 最大M值(用于L-BFGS) +``` + +### 2. 定义优化问题 + +GCTL优化库通过类的虚函数接口来定义具体的优化问题。不同类型的优化问题需要实现不同的虚函数接口: + +#### 2.1 线性问题接口 + +对于求解线性方程组 Ax = b 的问题: + +```cpp +class LinearProblem : public gctl::lcg_solver { +public: + // 必须实现:定义矩阵向量乘积 Ax + virtual void LCG_Ax(const gctl::array &x, + gctl::array &ax) override { + // 示例:实现 ax = A * x + for(size_t i = 0; i < n; ++i) { + ax[i] = 0.0; + for(size_t j = 0; j < n; ++j) { + ax[i] += A[i][j] * x[j]; + } + } + } + + // 可选实现:定义预处理矩阵M的作用 + virtual void LCG_Mx(const gctl::array &x, + gctl::array &mx) override { + // 示例:对角预处理 + for(size_t i = 0; i < n; ++i) { + mx[i] = x[i] / A[i][i]; + } + } +}; +``` + +#### 2.2 非线性优化问题接口 + +对于求解非线性优化问题 min f(x) 的情况: + +```cpp +class NonlinearProblem : public gctl::lbfgs_solver { +public: + // 必须实现:计算目标函数值和梯度 + virtual double LBFGS_Evaluate(const gctl::array &x, + gctl::array &g) override { + // 示例:Rosenbrock函数及其梯度 + double fx = 0.0; + for(size_t i = 0; i < n-1; ++i) { + fx += 100.0 * pow(x[i+1] - x[i]*x[i], 2) + + pow(1.0 - x[i], 2); + } + + // 计算梯度 + for(size_t i = 0; i < n; ++i) { + if(i == 0) { + g[i] = -400.0*x[i]*(x[i+1] - x[i]*x[i]) - + 2.0*(1.0 - x[i]); + } + else if(i == n-1) { + g[i] = 200.0*(x[i] - x[i-1]*x[i-1]); + } + else { + g[i] = 200.0*(x[i] - x[i-1]*x[i-1]) - + 400.0*x[i]*(x[i+1] - x[i]*x[i]) - + 2.0*(1.0 - x[i]); + } + } + return fx; + } + + // 可选实现:定义预处理 + virtual void LBFGS_Precondition(const gctl::array &x, + const gctl::array &g, + const gctl::array &d, + gctl::array &d_pre) override { + // 实现预处理 + d_pre = d; // 默认不做预处理 + } +}; +``` + +#### 2.3 全局优化问题接口 + +对于需要进行全局搜索的优化问题: + +```cpp +class GlobalProblem : public gctl::lgd_solver { +public: + // 必须实现:计算目标函数值和梯度 + virtual double LGD_Evaluate(const gctl::array &x, + gctl::array &g) override { + // 示例:多峰函数及其梯度 + double fx = 0.0; + for(size_t i = 0; i < n; ++i) { + fx += sin(x[i]) * exp(-0.1 * x[i]*x[i]); + } + + // 计算梯度 + for(size_t i = 0; i < n; ++i) { + g[i] = cos(x[i]) * exp(-0.1 * x[i]*x[i]) - + 0.2 * x[i] * sin(x[i]) * exp(-0.1 * x[i]*x[i]); + } + return -fx; // 最小化负值等价于最大化原函数 + } + + // 可选实现:监控优化进度 + virtual int LGD_Progress(const int curr_t, const double curr_fx, + const double mean_fx, const double best_fx, + const lgd_para ¶m) override { + // 返回非零值将终止优化 + return 0; + } +}; +``` + +#### 2.4 随机优化问题接口 + +对于需要随机采样或批量处理的优化问题: + +```cpp +class StochasticProblem : public gctl::sgd_solver { +public: + // 必须实现:计算单个批次的损失 + virtual double evaluate_batch(const gctl::array &x, + const gctl::array &batch_indices) override { + // 示例:均方误差损失 + double loss = 0.0; + for(auto idx : batch_indices) { + double pred = predict(x, data[idx]); + loss += 0.5 * pow(pred - target[idx], 2); + } + return loss / batch_indices.size(); + } + + // 必须实现:计算单个批次的梯度 + virtual void gradient_batch(const gctl::array &x, + const gctl::array &batch_indices, + gctl::array &grad) override { + // 示例:均方误差损失的梯度 + grad.fill(0.0); + for(auto idx : batch_indices) { + double pred = predict(x, data[idx]); + update_gradient(x, data[idx], pred - target[idx], grad); + } + grad *= (1.0 / batch_indices.size()); + } +}; +``` + +### 3. 基本用法 + +#### 2.1 线性共轭梯度法 (LCG) + +```cpp +#include + +// 继承lcg_solver类并实现必要的虚函数 +class MyProblem : public gctl::lcg_solver { +public: + // 实现矩阵向量乘法 Ax + virtual void LCG_Ax(const gctl::array &x, gctl::array &ax) override { + // 实现 ax = A * x + } + + // 实现预处理矩阵乘法 Mx(可选) + virtual void LCG_Mx(const gctl::array &x, gctl::array &mx) override { + // 实现预处理,如果不需要预处理,可以简单地将mx = x + mx = x; + } +}; + +// 使用求解器 +void solve() { + MyProblem solver; + solver.set_max_iterations(1000); + solver.set_epsilon(1e-6); + solver.solve(b, x); // b为右端向量,x为解向量 +} +``` + +#### 2.2 复数域线性共轭梯度法 (CLCG) + +```cpp +#include + +class ComplexProblem : public gctl::clcg_solver { +public: + virtual void CLCG_Ax(const gctl::array> &x, + gctl::array> &ax) override { + // 实现复数域的矩阵向量乘法 + } +}; +``` + +#### 2.3 L-BFGS优化器 + +```cpp +#include + +class OptProblem : public gctl::lbfgs_solver { +public: + // 计算目标函数值 + virtual double evaluate(const gctl::array &x) override { + // 返回在点x处的函数值 + } + + // 计算梯度 + virtual void gradient(const gctl::array &x, + gctl::array &grad) override { + // 计算在点x处的梯度 + } +}; +``` + +#### 2.4 Lévy梯度下降 (LGD) + +```cpp +#include + +class LGDProblem : public gctl::lgd_solver { +public: + // 计算目标函数值 + virtual double evaluate(const gctl::array &x) override { + // 返回在点x处的函数值 + } + + // 计算梯度 + virtual void gradient(const gctl::array &x, + gctl::array &grad) override { + // 计算在点x处的梯度 + } + + // 设置Lévy飞行参数 + void setup() { + set_levy_alpha(1.5); // 设置Lévy分布的α参数 + set_step_size(0.1); // 设置步长 + } +}; +``` + +#### 2.5 随机梯度下降 (SGD) + +```cpp +#include + +class SGDProblem : public gctl::sgd_solver { +public: + // 计算随机批次的损失 + virtual double evaluate_batch(const gctl::array &x, + const gctl::array &batch_indices) override { + // 返回当前批次的损失值 + } + + // 计算随机批次的梯度 + virtual void gradient_batch(const gctl::array &x, + const gctl::array &batch_indices, + gctl::array &grad) override { + // 计算当前批次的梯度 + } + + // 配置SGD参数 + void setup() { + set_batch_size(32); // 设置批次大小 + set_learning_rate(0.01); // 设置学习率 + set_momentum(0.9); // 设置动量(可选) + } +}; +``` + +### 3. 高级功能 + +#### 3.1 自定义损失函数 + +```cpp +#include + +class CustomLoss : public gctl::loss_function { +public: + virtual double evaluate(const gctl::array &pred, + const gctl::array &target) override { + // 实现自定义损失函数计算 + } + + virtual void gradient(const gctl::array &pred, + const gctl::array &target, + gctl::array &grad) override { + // 实现损失函数关于预测值的梯度计算 + } +}; +``` + +#### 3.2 矩阵分解工具使用 + +```cpp +#include + +void matrix_operations() { + // SVD分解 + gctl::matrix A, U, S, V; + gctl::svd_decomp(A, U, S, V); + + // LU分解 + gctl::matrix L, U; + gctl::lu_decomp(A, L, U); + + // Cholesky分解 + gctl::matrix L; + gctl::cholesky_decomp(A, L); +} +``` + +更多详细示例请参考 `example` 目录下的示例代码。 + +## 示例说明 + +- `ex1.cpp`: 基本的共轭梯度求解示例 +- `ex2.cpp`: L-BFGS优化示例 +- `ex3.cpp`: SVD分解应用 +- `ex4.cpp`: 随机梯度下降示例 +- `ex5.cpp`: 约束优化问题 +- `ex6.cpp`: 莱维梯度下降示例 +- `ex7.cpp-ex10.cpp`: 更多高级应用示例 + +## 许可证 + +该项目采用双重许可: +1. GNU Lesser General Public License v2.0 +2. 商业许可(需单独申请) + +## 联系方式 + +作者:Yi Zhang (yizhang-geo@zju.edu.cn) + +## 参与贡献 + +欢迎提交Issue和Pull Request来帮助改进项目。 \ No newline at end of file