/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * Geophysical Computational Tools & Library (GCTL) * * Copyright (c) 2022 Yi Zhang (yizhang-geo@zju.edu.cn) * * GCTL is distributed under a dual licensing scheme. You can redistribute * it and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 2 * of the License, or (at your option) any later version. You should have * received a copy of the GNU Lesser General Public License along with this * program. If not, see . * * If the terms and conditions of the LGPL v.2. would prevent you from using * the GCTL, please consider the option to obtain a commercial license for a * fee. These licenses are offered by the GCTL's original author. As a rule, * licenses are provided "as-is", unlimited in time for a one time fee. Please * send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget * to include some description of your company and the realm of its activities. * Also add information on how to contact you by electronic and paper mail. ******************************************************/ #include "lcg.h" #include "typeinfo" /** * Default parameter for conjugate gradient methods */ static const gctl::lcg_para lcg_defparam = {0, 1e-8, 0, 1e-6, 1.0, 0.95, 0.9, 10}; gctl::lcg_solver::lcg_solver() { lcg_param_ = lcg_defparam; lcg_inter_ = 1; lcg_msg_ = LCG_ITERATION; } gctl::lcg_solver::~lcg_solver(){} void gctl::lcg_solver::LCG_Mx(const array &x, array &mx) { throw std::runtime_error("The preconditioning function 'void gctl::lcg_solver::LCG_Mx(const array &x, array &mx)' must be defined defore using."); return; } int gctl::lcg_solver::LCG_Progress(const array &m, const double converge, const lcg_para ¶m, size_t t, std::ostream &ss) { std::string ss_str = typeid(ss).name(); if (ss_str.find("ofstream") != std::string::npos) { if (lcg_msg_ > LCG_ERROR && converge <= param.epsilon) // lcg_msg_ == LCG_SOLUTION { ss << "Iterations: " << std::setw(6) << t << ", Convergence: " << converge; } } else if (lcg_msg_ > LCG_ERROR) { if (converge <= param.epsilon) // lcg_msg_ == LCG_SOLUTION { ss << GCTL_CLEARLINE << "\rIterations: " << std::setw(6) << t << ", Convergence: " << converge << std::endl; return 0; } if (lcg_msg_ == LCG_ITERATION && lcg_inter_ > 0 && t%lcg_inter_ == 0) { ss << GCTL_CLEARLINE << "\rIterations: " << std::setw(6) << t << ", Convergence: " << converge; } } return 0; } void gctl::lcg_solver::set_lcg_message(lcg_message_type msg) { lcg_msg_ = msg; return; } void gctl::lcg_solver::set_lcg_report_interval(size_t inter) { lcg_inter_ = inter; return; } void gctl::lcg_solver::set_lcg_para(const lcg_para &in_param) { lcg_param_ = in_param; return; } gctl::lcg_para gctl::lcg_solver::default_lcg_para() { lcg_para dp = lcg_defparam; return dp; } #ifdef GCTL_OPTIMIZATION_TOML void gctl::lcg_solver::set_lcg_para(std::string filename) { toml::value toml_data; toml_data = toml::parse(filename); set_lcg_para(toml_data); return; } void gctl::lcg_solver::set_lcg_para(const toml::value &toml_data) { lcg_param_ = lcg_defparam; std::string LCG = "lcg"; if (toml_data.contains(LCG)) { if (toml_data.at(LCG).contains("max_iterations")) lcg_param_.max_iterations = toml::find(toml_data, LCG, "max_iterations"); if (toml_data.at(LCG).contains("epsilon")) lcg_param_.epsilon = toml::find(toml_data, LCG, "epsilon"); if (toml_data.at(LCG).contains("abs_diff")) lcg_param_.abs_diff = toml::find(toml_data, LCG, "abs_diff"); if (toml_data.at(LCG).contains("restart_epsilon")) lcg_param_.restart_epsilon = toml::find(toml_data, LCG, "restart_epsilon"); if (toml_data.at(LCG).contains("step")) lcg_param_.step = toml::find(toml_data, LCG, "step"); if (toml_data.at(LCG).contains("sigma")) lcg_param_.sigma = toml::find(toml_data, LCG, "sigma"); if (toml_data.at(LCG).contains("beta")) lcg_param_.beta = toml::find(toml_data, LCG, "beta"); if (toml_data.at(LCG).contains("maxi_m")) lcg_param_.maxi_m = toml::find(toml_data, LCG, "maxi_m"); } return; } #endif // GCTL_OPTIMIZATION_TOML void gctl::lcg_solver::lcg_error_str(lcg_return_code err_code, std::ostream &ss) { std::string ss_str = typeid(ss).name(); #if defined _WINDOWS || __WIN32__ if (lcg_msg_ > LCG_ERROR) { if (ss_str.find("ofstream") != std::string::npos) { if (err_code >= 0) ss << "LCG Success! "; else ss << "LCG Fail! "; } else { if (err_code >= 0) { SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN); ss << "LCG Success! "; } else { SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED); ss << "LCG Fail! "; } } } #else if (lcg_msg_ > LCG_ERROR) { if (ss_str.find("ofstream") != std::string::npos) { if (err_code >= 0) ss << "LCG Success! "; else ss << "LCG Fail! "; } else { if (err_code >= 0) ss << "\033[1m\033[32mLCG Success! "; else ss << "\033[1m\033[31mLCG Fail! "; } } #endif std::string err_str; switch (err_code) { case LCG_SUCCESS: err_str = "Iteration reached convergence."; break; case LCG_STOP: err_str = "Iteration is stopped by the progress evaluation function."; break; case LCG_ALREADY_OPTIMIZIED: err_str = "The variables are already optimized."; break; case LCG_UNKNOWN_ERROR: err_str = "Unknown error."; break; case LCG_INVILAD_VARIABLE_SIZE: err_str = "The size of the variables is negative."; break; case LCG_INVILAD_MAX_ITERATIONS: err_str = "The maximal iteration times can't be negative."; break; case LCG_INVILAD_EPSILON: err_str = "The epsilon is not in the range (0, 1)."; break; case LCG_INVILAD_RESTART_EPSILON: err_str = "The restart threshold can't be negative."; break; case LCG_REACHED_MAX_ITERATIONS: err_str = "The maximal iteration has been reached."; break; case LCG_NULL_PRECONDITION_MATRIX: err_str = "The precondition matrix can't be null."; break; case LCG_NAN_VALUE: err_str = "The model values are NaN."; break; case LCG_INVALID_POINTER: err_str = "Invalid pointer."; break; case LCG_INVALID_LAMBDA: err_str = "Invalid value for lambda."; break; case LCG_INVALID_SIGMA: err_str = "Invalid value for sigma."; break; case LCG_INVALID_BETA: err_str = "Invalid value for beta."; break; case LCG_INVALID_MAXIM: err_str = "Invalid value for maxi_m."; break; case LCG_SIZE_NOT_MATCH: err_str = "The sizes of solution and target do not match."; break; default: err_str = "Unknown error."; break; } if (lcg_msg_ == LCG_THROW && err_code < 0) throw std::runtime_error(err_str.c_str()); else if (lcg_msg_ == LCG_ERROR && err_code < 0) ss << err_str; else if (lcg_msg_ > LCG_ERROR) ss << err_str; #if defined _WINDOWS || __WIN32__ if (lcg_msg_ > LCG_ERROR) { if (ss_str.find("ofstream") != std::string::npos) { ss << " "; } else { SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), 7); ss << std::endl; } } #else if (lcg_msg_ > LCG_ERROR) { if (ss_str.find("ofstream") != std::string::npos) ss << " "; else ss << "\033[0m" << std::endl; } #endif return; } void gctl::lcg_solver::LCG_Minimize(array &m, const array &b, lcg_solver_type solver_id, std::ostream &ss) { // 使用lcg求解 注意当我们使用函数指针来调用求解函数时默认参数不可以省略 #ifdef GCTL_OPENMP double start = omp_get_wtime(); if (solver_id == LCG_CG) lcg(m ,b, ss); else if (solver_id == LCG_CGS) lcgs(m, b, ss); else if (solver_id == LCG_PCG) lpcg(m, b, ss); else if (solver_id == LCG_BICGSTAB) lbicgstab(m, b, ss); else if (solver_id == LCG_BICGSTAB2) lbicgstab2(m, b, ss); else throw std::invalid_argument("Invalid solver type."); double end = omp_get_wtime(); double costime = 1000*(end-start); #else clock_t start = clock(); if (solver_id == LCG_CG) lcg(m ,b, ss); else if (solver_id == LCG_CGS) lcgs(m, b, ss); else if (solver_id == LCG_PCG) lpcg(m, b, ss); else if (solver_id == LCG_BICGSTAB) lbicgstab(m, b, ss); else if (solver_id == LCG_BICGSTAB2) lbicgstab2(m, b, ss); else throw std::invalid_argument("Invalid solver type."); clock_t end = clock(); double costime = 1000*(end-start)/(double)CLOCKS_PER_SEC; #endif if (lcg_msg_ > LCG_ERROR) { switch (solver_id) { case LCG_CG: ss << "Solver: " << std::setw(9) << "CG, Time cost: " << costime << " ms\n"; break; case LCG_CGS: ss << "Solver: " << std::setw(9) << "CGS, Time cost: " << costime << " ms\n"; break; case LCG_PCG: ss << "Solver: " << std::setw(9) << "PCG, Time cost: " << costime << " ms\n"; break; case LCG_BICGSTAB: ss << "Solver: " << std::setw(9) << "BICGSTAB, Times cost: " << costime << " ms\n"; break; case LCG_BICGSTAB2: ss << "Solver: " << std::setw(9) << "BICGSTAB2, Time cost: " << costime << " ms\n"; break; default: ss << "Solver: " << std::setw(9) << "Unknown, Time cost: " << costime << " ms\n"; break; } } return; } void gctl::lcg_solver::LCG_MinimizeConstrained(array &m, const array &b, const array &low, const array &hig, lcg_solver_type solver_id, std::ostream &ss) { // 使用lcg求解 注意当我们使用函数指针来调用求解函数时默认参数不可以省略 #ifdef GCTL_OPENMP double start = omp_get_wtime(); if (solver_id == LCG_PG) lpg(m ,b, low, hig, ss); else if (solver_id == LCG_SPG) lspg(m, b, low, hig, ss); else throw std::invalid_argument("Invalid solver type."); double end = omp_get_wtime(); double costime = 1000*(end-start); #else clock_t start = clock(); if (solver_id == LCG_PG) lpg(m ,b, low, hig, ss); else if (solver_id == LCG_SPG) lspg(m, b, low, hig, ss); else throw std::invalid_argument("Invalid solver type."); clock_t end = clock(); double costime = 1000*(end-start)/(double)CLOCKS_PER_SEC; #endif if (lcg_msg_ > LCG_ERROR) { switch (solver_id) { case LCG_PG: ss << "Solver: " << std::setw(9) << "PG" << ", Time cost: " << costime << " ms\n"; break; case LCG_SPG: ss << "Solver: " << std::setw(9) << "SPG" << ", Time cost: " << costime << " ms\n"; break; default: ss << "Solver: " << std::setw(9) << "Unknown" << ", Time cost: " << costime << " ms\n"; break; } } return; } void gctl::lcg_solver::lcg(array &m, const array &B, std::ostream &ss) { size_t n_size = B.size(); //check parameters if (n_size <= 0) return lcg_error_str(LCG_INVILAD_VARIABLE_SIZE, ss); if (n_size != m.size()) return lcg_error_str(LCG_SIZE_NOT_MATCH, ss); if (lcg_param_.max_iterations < 0) return lcg_error_str(LCG_INVILAD_MAX_ITERATIONS, ss); if (lcg_param_.epsilon <= 0.0 || lcg_param_.epsilon >= 1.0) return lcg_error_str(LCG_INVILAD_EPSILON, ss); // locate memory gk.resize(n_size); dk.resize(n_size); Adk.resize(n_size); LCG_Ax(m, Adk); vecdiff(gk, Adk, B); veccpy(dk, gk, -1.0); double gk_mod = vecdot(gk, gk); double g0_mod = gk_mod; if (g0_mod < 1.0) g0_mod = 1.0; size_t t = 0; double dTAd, ak, betak, gk1_mod, residual; while (1) { if (lcg_param_.abs_diff) residual = sqrt(gk_mod)/n_size; else residual = gk_mod/g0_mod; if (LCG_Progress(m, residual, lcg_param_, t, ss)) { return lcg_error_str(LCG_STOP, ss); } if (residual <= lcg_param_.epsilon) { if (t == 0) return lcg_error_str(LCG_ALREADY_OPTIMIZIED, ss); else return lcg_error_str(LCG_CONVERGENCE, ss); } if (lcg_param_.max_iterations > 0 && t+1 > lcg_param_.max_iterations) { return lcg_error_str(LCG_REACHED_MAX_ITERATIONS, ss); } t++; LCG_Ax(dk, Adk); dTAd = vecdot(dk, Adk); ak = gk_mod/dTAd; vecapp(m, dk, ak); vecapp(gk, Adk, ak); if (!vecvalid(m)) { return lcg_error_str(LCG_NAN_VALUE, ss); } gk1_mod = vecdot(gk, gk); betak = gk1_mod/gk_mod; gk_mod = gk1_mod; vecdiff(dk, dk, gk, betak); } return lcg_error_str(LCG_UNKNOWN_ERROR, ss); } void gctl::lcg_solver::lpcg(array &m, const array &B, std::ostream &ss) { size_t n_size = B.size(); //check parameters if (n_size <= 0) return lcg_error_str(LCG_INVILAD_VARIABLE_SIZE, ss); if (n_size != m.size()) return lcg_error_str(LCG_SIZE_NOT_MATCH, ss); if (lcg_param_.max_iterations < 0) return lcg_error_str(LCG_INVILAD_MAX_ITERATIONS, ss); if (lcg_param_.epsilon <= 0.0 || lcg_param_.epsilon >= 1.0) return lcg_error_str(LCG_INVILAD_EPSILON, ss); // locate memory rk.resize(n_size); zk.resize(n_size); dk.resize(n_size); Adk.resize(n_size); LCG_Ax(m, Adk); vecdiff(rk, B, Adk); LCG_Mx(rk, zk); veccpy(dk, zk); double rk_mod = vecdot(rk, rk); double r0_mod = rk_mod; if (r0_mod < 1.0) r0_mod = 1.0; double zTr = vecdot(zk, rk); size_t t = 0; double dTAd, ak, betak, zTr1, residual; while (1) { if (lcg_param_.abs_diff) residual = sqrt(rk_mod)/n_size; else residual = rk_mod/r0_mod; if (LCG_Progress(m, residual, lcg_param_, t, ss)) { return lcg_error_str(LCG_STOP, ss); } if (residual <= lcg_param_.epsilon) { if (t == 0) return lcg_error_str(LCG_ALREADY_OPTIMIZIED, ss); return lcg_error_str(LCG_CONVERGENCE, ss); } if (lcg_param_.max_iterations > 0 && t+1 > lcg_param_.max_iterations) { return lcg_error_str(LCG_REACHED_MAX_ITERATIONS, ss); } t++; LCG_Ax(dk, Adk); dTAd = vecdot(dk, Adk); ak = zTr/dTAd; vecapp(m, dk, ak); vecapp(rk, Adk, -1.0*ak); LCG_Mx(rk, zk); rk_mod = vecdot(rk, rk); if (!vecvalid(m)) { return lcg_error_str(LCG_NAN_VALUE, ss); } zTr1 = vecdot(zk, rk); betak = zTr1/zTr; zTr = zTr1; vecadd(dk, zk, dk, 1.0, betak); } return lcg_error_str(LCG_UNKNOWN_ERROR, ss); } void gctl::lcg_solver::lcgs(array &m, const array &B, std::ostream &ss) { size_t n_size = B.size(); //check parameters if (n_size <= 0) return lcg_error_str(LCG_INVILAD_VARIABLE_SIZE, ss); if (n_size != m.size()) return lcg_error_str(LCG_SIZE_NOT_MATCH, ss); if (lcg_param_.max_iterations < 0) return lcg_error_str(LCG_INVILAD_MAX_ITERATIONS, ss); if (lcg_param_.epsilon <= 0.0 || lcg_param_.epsilon >= 1.0) return lcg_error_str(LCG_INVILAD_EPSILON, ss); rk.resize(n_size); r0_T.resize(n_size); pk.resize(n_size); vk.resize(n_size); Apx.resize(n_size); uk.resize(n_size); qk.resize(n_size); wk.resize(n_size); LCG_Ax(m, Apx); // 假设p0和q0为零向量 则在第一次迭代是pk和uk都等于rk // 所以我们能直接从计算Apx开始迭代 vecdiff(rk, B, Apx); veccpy(r0_T, rk); veccpy(uk, rk); veccpy(pk, rk); double rkr0_T = vecdot(rk, r0_T); double rk_mod = vecdot(rk, rk); double r0_mod = rk_mod; if (r0_mod < 1.0) r0_mod = 1.0; size_t t = 0; double ak, rk_abs, rkr0_T1, Apr_T, betak, residual; while (1) { if (lcg_param_.abs_diff) residual = sqrt(rk_mod)/n_size; else residual = rk_mod/r0_mod; if (LCG_Progress(m, residual, lcg_param_, t, ss)) { return lcg_error_str(LCG_STOP, ss); } if (residual <= lcg_param_.epsilon) { if (t == 0) return lcg_error_str(LCG_ALREADY_OPTIMIZIED, ss); return lcg_error_str(LCG_CONVERGENCE, ss); } if (lcg_param_.max_iterations > 0 && t+1 > lcg_param_.max_iterations) { return lcg_error_str(LCG_REACHED_MAX_ITERATIONS, ss); } t++; LCG_Ax(pk, Apx); Apr_T = vecdot(Apx, r0_T); ak = rkr0_T/Apr_T; vecdiff(qk, uk, Apx, 1.0, ak); vecadd(wk, uk, qk); LCG_Ax(wk, Apx); vecapp(m, wk, ak); vecapp(rk, Apx, -1.0*ak); rk_mod = vecdot(rk, rk); if (!vecvalid(m)) { return lcg_error_str(LCG_NAN_VALUE, ss); } rkr0_T1 = vecdot(rk, r0_T); betak = rkr0_T1/rkr0_T; rkr0_T = rkr0_T1; vecadd(uk, rk, qk, 1.0, betak); vecadd(vk, qk, pk, 1.0, betak); vecadd(pk, uk, vk, 1.0, betak); } return lcg_error_str(LCG_UNKNOWN_ERROR, ss); } void gctl::lcg_solver::lbicgstab(array &m, const array &B, std::ostream &ss) { size_t n_size = B.size(); //check parameters if (n_size <= 0) return lcg_error_str(LCG_INVILAD_VARIABLE_SIZE, ss); if (n_size != m.size()) return lcg_error_str(LCG_SIZE_NOT_MATCH, ss); if (lcg_param_.max_iterations < 0) return lcg_error_str(LCG_INVILAD_MAX_ITERATIONS, ss); if (lcg_param_.epsilon <= 0.0 || lcg_param_.epsilon >= 1.0) return lcg_error_str(LCG_INVILAD_EPSILON, ss); rk.resize(n_size); r0_T.resize(n_size); pk.resize(n_size); Adk.resize(n_size); sk.resize(n_size); Apx.resize(n_size); yk.resize(n_size); LCG_Ax(m, Adk); vecdiff(rk, B, Adk); veccpy(pk, rk); veccpy(r0_T, rk); double rkr0_T = vecdot(rk, r0_T); double rk_mod = vecdot(rk, rk); double r0_mod = rk_mod; if (r0_mod < 1.0) r0_mod = 1.0; size_t t = 0; double ak, wk, rkr0_T1, Apr_T, betak, Ass, AsAs, residual; while(1) { if (lcg_param_.abs_diff) residual = sqrt(rk_mod)/n_size; else residual = rk_mod/r0_mod; if (LCG_Progress(m, residual, lcg_param_, t, ss)) { return lcg_error_str(LCG_STOP, ss); } if (residual <= lcg_param_.epsilon) { if (t == 0) return lcg_error_str(LCG_ALREADY_OPTIMIZIED, ss); else return lcg_error_str(LCG_CONVERGENCE, ss); } if (lcg_param_.max_iterations > 0 && t+1 > lcg_param_.max_iterations) { return lcg_error_str(LCG_REACHED_MAX_ITERATIONS, ss); } t++; LCG_Ax(pk, Apx); Apr_T = vecdot(Apx, r0_T); ak = rkr0_T/Apr_T; vecdiff(sk, rk, Apx, 1.0, ak); LCG_Ax(sk, Adk); Ass = vecdot(Adk, sk); AsAs = vecdot(Adk, Adk); wk = Ass/AsAs; vecapp(m, pk, ak); vecapp(m, sk, wk); if (!vecvalid(m)) { return lcg_error_str(LCG_NAN_VALUE, ss); } vecdiff(rk, sk, Adk, 1.0, wk); rk_mod = vecdot(rk, rk); rkr0_T1 = vecdot(rk, r0_T); betak = (ak/wk)*rkr0_T1/rkr0_T; rkr0_T = rkr0_T1; vecdiff(yk, pk, Apx, 1.0, wk); vecadd(pk, rk, yk, 1.0, betak); } return lcg_error_str(LCG_UNKNOWN_ERROR, ss); } void gctl::lcg_solver::lbicgstab2(array &m, const array &B, std::ostream &ss) { size_t n_size = B.size(); //check parameters if (n_size <= 0) return lcg_error_str(LCG_INVILAD_VARIABLE_SIZE, ss); if (lcg_param_.max_iterations < 0) return lcg_error_str(LCG_INVILAD_MAX_ITERATIONS, ss); if (lcg_param_.epsilon <= 0.0 || lcg_param_.epsilon >= 1.0) return lcg_error_str(LCG_INVILAD_EPSILON, ss); if (lcg_param_.restart_epsilon <= 0.0) return lcg_error_str(LCG_INVILAD_RESTART_EPSILON, ss); rk.resize(n_size); r0_T.resize(n_size); pk.resize(n_size); Adk.resize(n_size); sk.resize(n_size); Apx.resize(n_size); yk.resize(n_size); LCG_Ax(m, Adk); vecdiff(rk, B, Adk); veccpy(pk, rk); veccpy(r0_T, rk); double rkr0_T = vecdot(rk, r0_T); double rk_mod = vecdot(rk, rk); double r0_mod = rk_mod; if (r0_mod < 1.0) r0_mod = 1.0; size_t t = 0; double ak, wk, rk_abs, rkr0_T1, Apr_T, betak; double Ass, AsAs, rr1_abs, residual; while(1) { if (lcg_param_.abs_diff) residual = sqrt(rk_mod)/n_size; else residual = rk_mod/r0_mod; if (LCG_Progress(m, residual, lcg_param_, t, ss)) { return lcg_error_str(LCG_STOP, ss); } if (residual <= lcg_param_.epsilon) { if (t == 0) return lcg_error_str(LCG_ALREADY_OPTIMIZIED, ss); else return lcg_error_str(LCG_CONVERGENCE, ss); } if (lcg_param_.max_iterations > 0 && t+1 > lcg_param_.max_iterations) { return lcg_error_str(LCG_REACHED_MAX_ITERATIONS, ss); } t++; LCG_Ax(pk, Apx); Apr_T = vecdot(Apx, r0_T); ak = rkr0_T/Apr_T; vecdiff(sk, rk, Apx, 1.0, ak); if (lcg_param_.abs_diff) { residual = vecdot(sk, sk); residual = sqrt(residual)/n_size; if (LCG_Progress(m, residual, lcg_param_, t, ss)) { if (t == 0) return lcg_error_str(LCG_ALREADY_OPTIMIZIED, ss); else return lcg_error_str(LCG_CONVERGENCE, ss); } if (residual <= lcg_param_.epsilon) { vecapp(m, pk, ak); if (!vecvalid(m)) { return lcg_error_str(LCG_NAN_VALUE, ss); } return lcg_error_str(LCG_CONVERGENCE, ss); } if (lcg_param_.max_iterations > 0 && t+1 > lcg_param_.max_iterations) { return lcg_error_str(LCG_REACHED_MAX_ITERATIONS, ss); } t++; } LCG_Ax(sk, Adk); Ass = vecdot(Adk, sk); AsAs = vecdot(Adk, Adk); wk = Ass/AsAs; vecapp(m, pk, ak); vecapp(m, sk, wk); if (!vecvalid(m)) { return lcg_error_str(LCG_NAN_VALUE, ss); } vecdiff(rk, sk, Adk, 1.0, wk); rk_mod = vecdot(rk, rk); rkr0_T1 = vecdot(rk, r0_T); rr1_abs = fabs(rkr0_T1); if (rr1_abs < lcg_param_.restart_epsilon) { veccpy(r0_T, rk); veccpy(pk, rk); rkr0_T1 = vecdot(rk, r0_T); betak = (ak/wk)*rkr0_T1/rkr0_T; rkr0_T = rkr0_T1; } else { betak = (ak/wk)*rkr0_T1/rkr0_T; rkr0_T = rkr0_T1; vecdiff(yk, pk, Apx, 1.0, wk); vecadd(pk, rk, yk, 1.0, betak); } } return lcg_error_str(LCG_UNKNOWN_ERROR, ss); } void gctl::lcg_solver::lpg(array &m, const array &B, const array &low, const array &hig, std::ostream &ss) { size_t n_size = B.size(); // check parameters if (n_size <= 0) return lcg_error_str(LCG_INVILAD_VARIABLE_SIZE, ss); if (n_size != m.size()) return lcg_error_str(LCG_SIZE_NOT_MATCH, ss); if (lcg_param_.max_iterations < 0) return lcg_error_str(LCG_INVILAD_MAX_ITERATIONS, ss); if (lcg_param_.epsilon <= 0.0) return lcg_error_str(LCG_INVILAD_EPSILON, ss); if (lcg_param_.step <= 0.0 || lcg_param_.epsilon >= 1.0) return lcg_error_str(LCG_INVALID_LAMBDA, ss); // locate memory gk.resize(n_size); Adk.resize(n_size); m_new.resize(n_size); gk_new.resize(n_size); sk.resize(n_size); yk.resize(n_size); double alpha_k = lcg_param_.step; vectop(m, hig); vecbtm(m, low); LCG_Ax(m, Adk); vecdiff(gk, Adk, B); double gk_mod = vecdot(gk, gk); double g0_mod = gk_mod; if (g0_mod < 1.0) g0_mod = 1.0; size_t t = 0; double sk_mod, syk_mod, residual; while(1) { if (lcg_param_.abs_diff) residual = sqrt(gk_mod)/n_size; else residual = gk_mod/g0_mod; if (LCG_Progress(m, residual, lcg_param_, t, ss)) { return lcg_error_str(LCG_STOP, ss); } if (residual <= lcg_param_.epsilon) { if (t == 0) return lcg_error_str(LCG_ALREADY_OPTIMIZIED, ss); else return lcg_error_str(LCG_CONVERGENCE, ss); } if (lcg_param_.max_iterations > 0 && t+1 > lcg_param_.max_iterations) { return lcg_error_str(LCG_REACHED_MAX_ITERATIONS, ss); } t++; vecdiff(m_new, m, gk, 1.0, alpha_k); vectop(m_new, hig); vecbtm(m_new, low); LCG_Ax(m_new, Adk); vecdiff(gk_new, Adk, B); vecdiff(sk, m_new, m); vecdiff(yk, gk_new, gk); sk_mod = vecdot(sk, sk); syk_mod = vecdot(sk, yk); alpha_k = sk_mod/syk_mod; veccpy(m, m_new); veccpy(gk, gk_new); gk_mod = vecdot(gk, gk); } return lcg_error_str(LCG_UNKNOWN_ERROR, ss); } void gctl::lcg_solver::lspg(array &m, const array &B, const array &low, const array &hig, std::ostream &ss) { size_t n_size = B.size(); // check parameters if (n_size <= 0) return lcg_error_str(LCG_INVILAD_VARIABLE_SIZE, ss); if (n_size != m.size()) return lcg_error_str(LCG_SIZE_NOT_MATCH, ss); if (lcg_param_.max_iterations < 0) return lcg_error_str(LCG_INVILAD_MAX_ITERATIONS, ss); if (lcg_param_.epsilon <= 0.0 || lcg_param_.epsilon >= 1.0) return lcg_error_str(LCG_INVILAD_EPSILON, ss); if (lcg_param_.step <= 0.0) return lcg_error_str(LCG_INVALID_LAMBDA, ss); if (lcg_param_.sigma <= 0.0 || lcg_param_.sigma >= 1.0) return lcg_error_str(LCG_INVALID_SIGMA, ss); if (lcg_param_.beta <= 0.0 || lcg_param_.beta >= 1.0) return lcg_error_str(LCG_INVALID_BETA, ss); if (lcg_param_.maxi_m <= 0) return lcg_error_str(LCG_INVALID_MAXIM, ss); // locate memory gk.resize(n_size); Adk.resize(n_size); m_new.resize(n_size); gk_new.resize(n_size); sk.resize(n_size); yk.resize(n_size); dk.resize(n_size); qk_m.resize(lcg_param_.maxi_m); double lambda_k = lcg_param_.step; double qk = 0; vectop(m, hig); vecbtm(m, low); LCG_Ax(m, Adk); vecdiff(gk, Adk, B); double gk_mod = vecdot(gk, gk); double g0_mod = gk_mod; if (g0_mod < 1.0) g0_mod = 1.0; // calculate qk double mAdk, Bm; mAdk = vecdot(m, Adk); Bm = vecdot(B, m); qk = 0.5*mAdk - Bm; qk_m[0] = qk; size_t i; for (i = 1; i < lcg_param_.maxi_m; i++) { qk_m[i] = -1e+30; } size_t t = 0; double alpha_k, maxi_qk, residual; double alpha_mod, sk_mod, syk_mod; while(1) { if (lcg_param_.abs_diff) residual = sqrt(gk_mod)/n_size; else residual = gk_mod/g0_mod; if (LCG_Progress(m, residual, lcg_param_, t, ss)) { return lcg_error_str(LCG_STOP, ss); } if (residual <= lcg_param_.epsilon) { if (t == 0) return lcg_error_str(LCG_ALREADY_OPTIMIZIED, ss); else return lcg_error_str(LCG_CONVERGENCE, ss); } if (lcg_param_.max_iterations > 0 && t+1 > lcg_param_.max_iterations) { return lcg_error_str(LCG_REACHED_MAX_ITERATIONS, ss); } t++; vecdiff(dk, m, gk, 1.0, lambda_k); vectop(dk, hig); vecbtm(dk, low); vecsub(dk, m); alpha_k = 1.0; vecadd(m_new, m, dk, 1.0, alpha_k); LCG_Ax(m_new, Adk); mAdk = vecdot(m_new, Adk); Bm = vecdot(B, m_new); qk = 0.5*mAdk - Bm; alpha_mod = vecdot(gk, dk); alpha_mod *= lcg_param_.sigma*alpha_k; maxi_qk = qk_m[0]; for (i = 1; i < lcg_param_.maxi_m; i++) { if (qk_m[i] > maxi_qk) maxi_qk = qk_m[i]; } while(qk > maxi_qk + alpha_mod) { alpha_k = alpha_k*lcg_param_.beta; vecadd(m_new, m, dk, 1.0, alpha_k); LCG_Ax(m_new, Adk); mAdk = vecdot(m_new, Adk); Bm = vecdot(B, m_new); qk = 0.5*mAdk - Bm; alpha_mod = vecdot(gk, dk); alpha_mod *= lcg_param_.sigma*alpha_k; } // put new values in qk_m qk_m[(t+1)%lcg_param_.maxi_m] = qk; vecdiff(gk_new, Adk, B); vecdiff(sk, m_new, m); vecdiff(yk, gk_new, gk); sk_mod = vecdot(sk, sk); syk_mod = vecdot(sk, yk); lambda_k = sk_mod/syk_mod; veccpy(m, m_new); veccpy(gk, gk_new); gk_mod = vecdot(gk, gk); } return lcg_error_str(LCG_UNKNOWN_ERROR, ss); }