19 Commits

Author SHA1 Message Date
a396674115 tmp update 2022-12-16 14:24:40 +08:00
9fd52d7121 update ignore 2022-11-02 10:46:14 +08:00
f27bc17948 update 2022-03-20 10:44:52 +08:00
24235f44ca tmp update 2022-02-17 16:47:20 +08:00
9d31decd84 tmp update 2022-02-17 09:31:36 +08:00
e3f737fbc0 tmp update 2022-02-16 20:52:34 +08:00
038fb4a60d tmp update 2022-02-16 17:06:41 +08:00
47b3e01cfb tmp update 2022-02-15 15:27:22 +08:00
aafcfc4279 update LibLBFGSConfig.cmake.in 2021-11-02 09:58:35 +08:00
fe17b3fe0c update cmakelists 2021-09-10 12:45:08 +08:00
2aea5ff2b9 Merge branch 'master' of https://gitee.com/yizhangss/liblbfgs 2021-08-28 12:43:16 +08:00
3c1de9f322 add config.cmake.in 2021-08-28 12:42:28 +08:00
4733fe57ac update build system 2021-08-02 21:54:09 +08:00
张壹
69a4b33b8f update build system 2021-08-01 10:25:17 +08:00
253b66d3c7 update sample3 2021-06-02 15:38:37 +08:00
71d0a5e3aa update cmakelists 2021-01-04 20:57:28 +08:00
pi
2ff925cdc4 update cmakelists 2020-09-09 17:28:50 +08:00
6083b80485 update on cmakelists 2020-09-09 12:23:23 +08:00
pi
5b958b10ab update annotations 2020-07-15 16:22:04 +08:00
10 changed files with 518 additions and 46 deletions

2
.gitignore vendored
View File

@@ -21,5 +21,7 @@
*.app
.vscode/
build/
.DS_Store
*.sh

View File

@@ -1,12 +1,19 @@
cmake_minimum_required(VERSION 3.15.2)
# 设置cxx编译器
# 如果你使用别的编译器,请在这里修改
set(CMAKE_C_COMPILER /usr/local/bin/gcc-9)
set(CMAKE_CXX_COMPILER /usr/local/bin/g++-9)
# 设置工程名称和语言
project(LIBLBFGS VERSION 1.1.0)
# 设置安装地址 改用homebrew安装后这一句就不需要了
# set(CMAKE_INSTALL_PREFIX /usr/local)
project(LibLBFGS VERSION 1.1.0)
# 添加配置配件编写的函数
include(CMakePackageConfigHelpers)
if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows")
set(CMAKE_INSTALL_PREFIX D:/Library)
else()
set(CMAKE_INSTALL_PREFIX /opt/stow/liblbfgs)
endif()
message(STATUS "Platform: " ${CMAKE_HOST_SYSTEM_NAME})
message(STATUS "Install prefix: " ${CMAKE_INSTALL_PREFIX})
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
# 添加编译选项
option(HAVE_CONFIG_H "use config.h" ON)
option(_MSC_VER "use __msc_ver" OFF)
@@ -16,5 +23,6 @@ configure_file(
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_SOURCE_DIR}/src/lib/config.h"
)
# 添加源文件地址
add_subdirectory(src/)

16
LibLBFGSConfig.cmake.in Normal file
View File

@@ -0,0 +1,16 @@
@PACKAGE_INIT@
set(@PROJECT_NAME@_VERSION "@PROJECT_VERSION@")
set_and_check(@PROJECT_NAME@_INSTALL_PREFIX "${PACKAGE_PREFIX_DIR}")
set_and_check(@PROJECT_NAME@_INC_DIR "${PACKAGE_PREFIX_DIR}/include")
set_and_check(@PROJECT_NAME@_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")
set_and_check(@PROJECT_NAME@_LIB_DIR "${PACKAGE_PREFIX_DIR}/lib")
set_and_check(@PROJECT_NAME@_LIBRARY_DIR "${PACKAGE_PREFIX_DIR}/lib")
set(@PROJECT_NAME@_LIB lbfgs)
set(@PROJECT_NAME@_LIBRARY lbfgs)
# include target information
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components(@PROJECT_NAME@)

View File

@@ -13,13 +13,52 @@ set_target_properties(lbfgs_static PROPERTIES OUTPUT_NAME "lbfgs")
set_target_properties(lbfgs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
set_target_properties(lbfgs_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
# 设置动态库的版本号
set_target_properties(lbfgs PROPERTIES VERSION 1.1 SOVERSION 1.1)
set_target_properties(lbfgs PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR})
# 设置动态库的运行搜索地址
set_target_properties(lbfgs PROPERTIES INSTALL_RPATH /usr/local/lib)
set_target_properties(lbfgs_static PROPERTIES INSTALL_RPATH /usr/local/lib)
# 设置库文件的输出地址
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
# 在LINUX中需添加math库
if(UNIX AND NOT APPLE)
message(STATUS "Linking math library.")
find_library(MATH_LIBRARY m)
find_library(MATH_A_LIBRARY libm.a)
target_link_libraries(lbfgs PUBLIC ${MATH_LIBRARY})
target_link_libraries(lbfgs_static ${MATH_A_LIBRARY})
endif()
# 添加编译命令
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
set(CONFIG_FILE_PATH lib/cmake/${PROJECT_NAME})
configure_package_config_file(${PROJECT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in
${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake
INSTALL_DESTINATION ${CONFIG_FILE_PATH})
write_basic_package_version_file(${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion)
# 库的安装命令
install(TARGETS lbfgs lbfgs_static
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
if(WIN32)
install(TARGETS lbfgs DESTINATION lib)
install(TARGETS lbfgs_static DESTINATION lib)
else()
install(TARGETS lbfgs lbfgs_static
EXPORT ${PROJECT_NAME}Targets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
install(EXPORT ${PROJECT_NAME}Targets
DESTINATION ${CONFIG_FILE_PATH})
install(FILES
${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake
${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
DESTINATION ${CONFIG_FILE_PATH})
endif()
# 头文件安装命令
install(FILES lib/lbfgs.h DESTINATION include)
@@ -27,23 +66,17 @@ install(FILES lib/lbfgs.h DESTINATION include)
# 设置可执行文件的输出地址
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# 添加可执行文件 命令行
add_executable(lbfgs_sample sample/sample.c)
# 为安装文件添加动态库的搜索地址
set_target_properties(lbfgs_sample PROPERTIES INSTALL_RPATH "/usr/local/lib")
# 链接动态库
target_link_libraries(lbfgs_sample PUBLIC lbfgs)
# 例子的编译方法
macro(add_sample name file)
# 添加可执行文件 命令行
add_executable(${name} sample/${file})
# 为安装文件添加动态库的搜索地址 在Windows下并没有什么用 直接忽略
set_target_properties(${name} PROPERTIES INSTALL_RPATH ${PACKAGE_PREFIX_DIR}/lib)
# 链接动态库
target_link_libraries(${name} PUBLIC lbfgs)
endmacro()
# 添加可执行文件 命令行
add_executable(lbfgs_sample2 sample/sample2.cpp)
# 为安装文件添加动态库的搜索地址
set_target_properties(lbfgs_sample2 PROPERTIES INSTALL_RPATH "/usr/local/lib")
# 链接动态库
target_link_libraries(lbfgs_sample2 PUBLIC lbfgs)
# 添加可执行文件 命令行
add_executable(lbfgs_sample3 sample/sample3.cpp)
# 为安装文件添加动态库的搜索地址
set_target_properties(lbfgs_sample3 PROPERTIES INSTALL_RPATH "/usr/local/lib")
# 链接动态库
target_link_libraries(lbfgs_sample3 PUBLIC lbfgs)
add_sample(lbfgs_sample sample.c)
add_sample(lbfgs_sample2 sample2.cpp)
add_sample(lbfgs_sample3 sample3.cpp)
add_sample(lbfgs_sample4 sample4.cpp)

View File

@@ -99,6 +99,7 @@ struct tag_callback_data {
void *instance; // 用户给出的运行实例
lbfgs_evaluate_t proc_evaluate; // 目标函数与模型梯度计算函数指针
lbfgs_progress_t proc_progress; // 迭代过程监控函数指针
lbfgs_precondition_t proc_precondition; // 预优函数指针
};
typedef struct tag_callback_data callback_data_t;
@@ -147,6 +148,20 @@ static int line_search_backtracking(
const lbfgs_parameter_t *param
);
static int line_search_backtracking_quad(
int n,
lbfgsfloatval_t *x,
lbfgsfloatval_t *f,
lbfgsfloatval_t *g,
lbfgsfloatval_t *s,
lbfgsfloatval_t *stp,
const lbfgsfloatval_t* xp,
const lbfgsfloatval_t* gp,
lbfgsfloatval_t *wa,
callback_data_t *cd,
const lbfgs_parameter_t *param
);
static int line_search_backtracking_owlqn(
int n,
lbfgsfloatval_t *x,
@@ -250,7 +265,8 @@ int lbfgs(
lbfgs_evaluate_t proc_evaluate,
lbfgs_progress_t proc_progress,
void *instance,
lbfgs_parameter_t *_param
lbfgs_parameter_t *_param,
lbfgs_precondition_t proc_precondition
)
{
int ret;
@@ -264,10 +280,13 @@ int lbfgs(
const int m = param.m;
lbfgsfloatval_t *xp = NULL;
lbfgsfloatval_t *g = NULL, *gp = NULL, *pg = NULL;
lbfgsfloatval_t *g = NULL, *gp = NULL, *pg = NULL; // gp (p for previous) pg (p for pesudo)
lbfgsfloatval_t *d = NULL, *w = NULL, *pf = NULL;
lbfgsfloatval_t *dp = NULL; // p for preconditioned (Add by Yi Zhang on 02-16-2022)
lbfgsfloatval_t *y2 = NULL; // Add by Yi Zhang on 02-16-2022
iteration_data_t *lm = NULL, *it = NULL;
lbfgsfloatval_t ys, yy;
lbfgsfloatval_t Yk; // Add by Yi Zhang on 02-16-2022
lbfgsfloatval_t xnorm, gnorm, beta;
lbfgsfloatval_t fx = 0.;
lbfgsfloatval_t rate = 0.;
@@ -280,6 +299,7 @@ int lbfgs(
cd.instance = instance;
cd.proc_evaluate = proc_evaluate;
cd.proc_progress = proc_progress;
cd.proc_precondition = proc_precondition;
#if defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__))
/* Round out the number of variables. */
@@ -364,6 +384,11 @@ int lbfgs(
case LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE:
linesearch = line_search_backtracking;
break;
case LBFGS_LINESEARCH_BACKTRACKING_ARMIJO_QUAD:
//case LBFGS_LINESEARCH_BACKTRACKING_WOLFE_QUAD:
//case LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE_QUAD:
linesearch = line_search_backtracking_quad;
break;
default:
return LBFGSERR_INVALID_LINESEARCH;
}
@@ -379,6 +404,23 @@ int lbfgs(
ret = LBFGSERR_OUTOFMEMORY;
goto lbfgs_exit;
}
// Add by Yi Zhang on 02-16-2022
y2 = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t));
if (y2 == NULL) {
ret = LBFGSERR_OUTOFMEMORY;
goto lbfgs_exit;
}
if (cd.proc_precondition) {
dp = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t));
if (dp == NULL) {
ret = LBFGSERR_OUTOFMEMORY;
goto lbfgs_exit;
}
}
// End
// 初始化计算L1模的数组
if (param.orthantwise_c != 0.) {
/* Allocate working space for OW-LQN. */
@@ -438,6 +480,7 @@ int lbfgs(
we assume the initial hessian matrix H_0 as the identity matrix.
*/
// 初始下降方向为梯度的反方向
// LBFGS中下降方向为 -1*H_k*g_k
if (param.orthantwise_c == 0.) {
vecncpy(d, g, n); //拷贝数组 并反号(乘-1
} else {
@@ -455,6 +498,7 @@ int lbfgs(
vec2norm(&gnorm, pg, n);
}
// 为啥要保证xnorm大于等于1不明白
// 答 参考头文件中的注释 如果模型参数的模长小于1则使用梯度的模长作为收敛性的测试指标
if (xnorm < 1.0) xnorm = 1.0;
// 如果输入x即为最优化的解 则退出
if (gnorm / xnorm <= param.epsilon) {
@@ -465,14 +509,14 @@ int lbfgs(
/* Compute the initial step:
step = 1.0 / sqrt(vecdot(d, d, n))
*/
// 计算估算的初始步长
// 计算估算的初始步长 这一步在实际应用中重要 在相似代码编写中需参考
vec2norminv(&step, d, n); // 计算数组L2模的倒数与注释的内容等效
k = 1;
end = 0;
for (;;) {
/* Store the current position and gradient vectors. */
veccpy(xp, x, n);
veccpy(xp, x, n); // p for previous
veccpy(gp, g, n);
/* Search for an optimal step. */
@@ -485,7 +529,8 @@ int lbfgs(
param.orthantwise_c, param.orthantwise_start, param.orthantwise_end
);
}
// 线性搜索错误 此时则退回到上一次迭代的位置并退出
// 返回值小于0则表示线性搜索错误 此时则退回到上一次迭代的位置并退出
if (ls < 0) {
/* Revert to the previous point. */
veccpy(x, xp, n);
@@ -560,6 +605,7 @@ int lbfgs(
s_{k+1} = x_{k+1} - x_{k} = \step * d_{k}.
y_{k+1} = g_{k+1} - g_{k}.
*/
// 计算最新保存的s和y
it = &lm[end];
vecdiff(it->s, x, xp, n); // 计算两个数组的差 it->s = x - xp
vecdiff(it->y, g, gp, n);
@@ -582,8 +628,12 @@ int lbfgs(
Mathematics of Computation, Vol. 35, No. 151,
pp. 773--782, 1980.
*/
// m小于迭代次数
bound = (m <= k) ? m : k;
++k;
// end+1等于m则将其重置为0 循环保存
end = (end + 1) % m;
/* Compute the steepest direction. */
@@ -605,7 +655,32 @@ int lbfgs(
vecadd(d, it->y, -it->alpha, n);
}
vecscale(d, ys / yy, n); // 适当缩放d的大小
// Annotated by Yi Zhang on 02-16-2022
//vecscale(d, ys / yy, n); // 适当缩放d的大小
// Add by Yi Zhang on 02-16-2022
// Wah June Leong & Chuei Yee Chen (2013) A class of diagonal preconditioners for limited memory BFGS method,
// Optimization Methods and Software, 28:2, 379-392, DOI: 10.1080/10556788.2011.653356
// 我们在这里提供一个预优函数的接口 需还原则删除下面的代码段 同时取消上面一行注释
if (cd.proc_precondition) {
if (param.orthantwise_c == 0.) {
cd.proc_precondition(cd.instance, x, g, d, dp, n);
} else {
cd.proc_precondition(cd.instance, x, pg, d, dp, n);
}
veccpy(d, dp, n);
} else if (ys < yy) {
// 这里假设了初始的Hessian矩阵为单位阵乘以ys/yy
vecscale(d, ys / yy, n); // 适当缩放d的大小
} else {
// 假设初始的Hessian矩阵为 I + [(ys - yy)/tr(Yk)]diag(y2)
veccpy(y2, lm[end].y, n);
vecmul(y2, lm[end].y, n);
vecdot(&Yk, y2, y2, n);
vecadd(d, y2, (ys-yy)/Yk, n);
}
// End
for (i = 0;i < bound;++i) {
it = &lm[j];
@@ -657,6 +732,14 @@ lbfgs_exit:
vecfree(g);
vecfree(xp);
// Add by Yi Zhang on 02-16-2022
vecfree(y2);
if (cd.proc_precondition) {
vecfree(dp);
}
// End
return ret;
}
@@ -881,6 +964,91 @@ static int line_search_backtracking(
}
}
static int line_search_backtracking_quad(
int n,
lbfgsfloatval_t *x,
lbfgsfloatval_t *f,
lbfgsfloatval_t *g,
lbfgsfloatval_t *s,
lbfgsfloatval_t *stp,
const lbfgsfloatval_t* xp,
const lbfgsfloatval_t* gp,
lbfgsfloatval_t *wp,
callback_data_t *cd,
const lbfgs_parameter_t *param
)
{
int count = 0;
lbfgsfloatval_t dg, stp2;
lbfgsfloatval_t finit, dginit = 0., dgtest;
const lbfgsfloatval_t dec = 0.5;
/* Check the input parameters for errors. */
if (*stp <= 0.) {
return LBFGSERR_INVALIDPARAMETERS;
}
/* Compute the initial gradient in the search direction. */
vecdot(&dginit, g, s, n); //计算点积 g为梯度方向 s为下降方向
/* Make sure that s points to a descent direction. */
if (0 < dginit) {
return LBFGSERR_INCREASEGRADIENT;
}
/* The initial value of the objective function. */
finit = *f;
dgtest = param->ftol * dginit; // ftol 大概为 function tolerance
for (;;) {
veccpy(x, xp, n);
vecadd(x, s, *stp, n); // vecadd x += (*stp)*s
/* Evaluate the function and gradient values. */
// 这里我们发现的cd的用法即传递函数指针
*f = cd->proc_evaluate(cd->instance, x, g, cd->n, *stp);
++count;
// 充分下降条件
if (*f > finit + *stp * dgtest) {
stp2 = 0.5*dginit*(*stp)*(*stp)/(finit - (*f) + dginit*(*stp));
if (stp2 < 0) {
(*stp) *= dec;
}
else {
(*stp) = stp2;
}
} else {
// 充分下降条件满足并搜索方法为backtracking搜索条件为Armijo则可以退出了。否则更新步长继续搜索。
/* The sufficient decrease condition (Armijo condition). */
if (param->linesearch == LBFGS_LINESEARCH_BACKTRACKING_ARMIJO_QUAD) {
/* Exit with the Armijo condition. */
return count;
}
}
// 以下情况返回的步长不能保证满足搜索条件
if (*stp < param->min_step) {
/* The step is the minimum value. */
// 退出 此时步长小于最小步长
return LBFGSERR_MINIMUMSTEP;
}
if (*stp > param->max_step) {
/* The step is the maximum value. */
// 退出 此时步长大于最大步长
return LBFGSERR_MAXIMUMSTEP;
}
if (param->max_linesearch <= count) {
/* Maximum number of iteration. */
// 退出 线性搜索次数超过了最大限制
return LBFGSERR_MAXIMUMLINESEARCH;
}
}
}
// 还是反向搜索 只是添加了L1模方向
static int line_search_backtracking_owlqn(
int n,

View File

@@ -35,6 +35,7 @@ extern "C" {
#endif/*__cplusplus*/
// 算法库使用的浮点类型定义
// 结合后面的定义可见我们现在使用的其实就是 double 类型
/*
* The default precision of floating point values is 64bit (double).
*/
@@ -196,6 +197,14 @@ enum {
* a is the step length.
*/
LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE = 3,
LBFGS_LINESEARCH_BACKTRACKING_ARMIJO_QUAD = 4,
//LBFGS_LINESEARCH_BACKTRACKING_QUAD = 5,
//LBFGS_LINESEARCH_BACKTRACKING_WOLFE_QUAD = 5,
//LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE_QUAD = 6,
};
// L-BFGS参数类型。参数很多简要说明如下
@@ -204,8 +213,8 @@ enum {
// past 以delta(不同迭代次数的目标函数值)为基础的迭代终止条件数past代表了以多少迭代次数之前的目标函数值作为delta计算的间隔默认值为0
// 即不以delta为迭代终止条件。
// delta (f' - f) / f 不同迭代次数时目标函数之差与当前目标函数值之比但past不为0时会计算。
// max_iterations 最大迭代次数
// linesearch 线性搜索方式,由此文件上部枚举类型定义。
// max_iterations 最大迭代次数为0时表示一直迭代到终止条件被满足或出现其他错误。
// linesearch 线性搜索方式,由此文件前述枚举类型定义。
// max_linesearch 每次迭代中线性搜索的最大次数默认值为40
// min_step 线性搜索中的最小步长默认值为1e-20
// max_step 线性搜索中的最大步长默认值为1e+20
@@ -462,6 +471,30 @@ typedef int (*lbfgs_progress_t)(
int ls
);
/**
* Callback interface to implement the preconditioning process.
*
* The lbfgs() function call this function for each iteration. Implementing
* this function, a client program can preform the preconditioning process.
*
* @param instance The user data sent for lbfgs() function by the client.
* @param x The current values of variables.
* @param g The current gradient values of variables.
* @param d The current values of search directions.
* @param d_pre The values of search directions being preconditioned.
* The callback function must compute these values.
* @param n The number of variables.
*/
typedef void (*lbfgs_precondition_t)(
void *instance,
const lbfgsfloatval_t *x,
const lbfgsfloatval_t *g,
const lbfgsfloatval_t *d,
lbfgsfloatval_t *d_pre,
const int n
);
/*
A user must implement a function compatible with ::lbfgs_evaluate_t (evaluation
callback) and pass the pointer to the callback function to lbfgs() arguments.
@@ -549,7 +582,8 @@ int lbfgs(
lbfgs_evaluate_t proc_evaluate,
lbfgs_progress_t proc_progress,
void *instance,
lbfgs_parameter_t *param
lbfgs_parameter_t *param,
lbfgs_precondition_t proc_precondition
);
// 将一个参数类型内的全部变量值重置为默认值

View File

@@ -71,7 +71,7 @@ int main(int argc, char *argv[])
Start the L-BFGS optimization; this will invoke the callback functions
evaluate() and progress() when necessary.
*/
ret = lbfgs(N, x, &fx, evaluate, progress, NULL, &param);
ret = lbfgs(N, x, &fx, evaluate, progress, NULL, &param, NULL);
/* Report the result. */
printf("L-BFGS optimization terminated with status code = %d\n", ret);

View File

@@ -39,10 +39,16 @@ public:
Start the L-BFGS optimization; this will invoke the callback functions
evaluate() and progress() when necessary.
*/
int ret = lbfgs(N, m_x, &fx, _evaluate, _progress, this, NULL);
lbfgs_parameter_t self_para;
lbfgs_parameter_init(&self_para);
self_para.epsilon = 1e-7;
//self_para.linesearch = LBFGS_LINESEARCH_BACKTRACKING_ARMIJO_QUAD;
//self_para.ftol = 1e-3;
int ret = lbfgs(N, m_x, &fx, _evaluate, _progress, this, &self_para, NULL);
/* Report the result. */
printf("L-BFGS optimization terminated with status code = %d\n", ret);
printf("L-BFGS optimization terminated with status: %s\n", lbfgs_strerror(ret));
printf(" fx = %f, x[0] = %f, x[1] = %f\n", fx, m_x[0], m_x[1]);
return ret;
@@ -111,7 +117,7 @@ protected:
{
printf("Iteration %d:\n", k);
printf(" fx = %f, x[0] = %f, x[1] = %f\n", fx, x[0], x[1]);
printf(" xnorm = %f, gnorm = %f, step = %f\n", xnorm, gnorm, step);
printf(" xnorm = %f, gnorm = %f, step = %f, convergence = %e\n", xnorm, gnorm, step, gnorm/xnorm);
printf("\n");
return 0;
}

View File

@@ -70,7 +70,7 @@ int TEST_FUNC::Progress(const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, cons
const lbfgsfloatval_t xnorm, const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step, const lbfgs_parameter_t param,
int n, int k, int ls)
{
clog << "iteration times: " << k << " fx = " << fx << " gnorm/xnorm = " << gnorm/xnorm << endl;
clog << "iteration times: " << k << " fx = " << fx << " gnorm/xnorm = " << gnorm/(xnorm>1.0?xnorm:1.0) << endl;
clog << x[0] << " " << x[1] << " " << x[2] << endl;
if (fx < 1e-10) return 1; //这里我们设置一个方程组的整体目标函数值作为终止条件 因为此方程组在0值处梯度不为0 无法使用梯度条件
@@ -83,11 +83,12 @@ int TEST_FUNC::Routine()
lbfgs_parameter_t self_para;
lbfgs_parameter_init(&self_para);
self_para.past = 2;
//self_para.min_step = 1e-30;
//self_para.max_linesearch = 40;
//self_para.linesearch = LBFGS_LINESEARCH_BACKTRACKING_WOLFE;
int ret = lbfgs(3, m_x, &fx, _Func, _Progress, this, &self_para);
int ret = lbfgs(3, m_x, &fx, _Func, _Progress, this, &self_para, NULL);
clog << "L-BFGS optimization terminated with status: " << endl << lbfgs_strerror(ret) << endl;
clog << m_x[0] << " " << m_x[1] << " " << m_x[2] << endl;

204
src/sample/sample4.cpp Normal file
View File

@@ -0,0 +1,204 @@
#include "iostream"
#include "cmath"
#include "ctime"
#include "random"
#include "../lib/lbfgs.h"
using std::clog;
using std::endl;
#define M 120
#define N 100
inline lbfgsfloatval_t scalernd(lbfgsfloatval_t l, lbfgsfloatval_t h)
{
return (h-l)*rand()*1.0/RAND_MAX + l;
}
inline void vecrnd(lbfgsfloatval_t *a, lbfgsfloatval_t l, lbfgsfloatval_t h, int n)
{
srand(time(nullptr));
for (size_t i = 0; i < n; i++)
{
a[i] = (h-l)*rand()*1.0/RAND_MAX + l;
}
return;
}
inline lbfgsfloatval_t max_diff(const lbfgsfloatval_t *a, const lbfgsfloatval_t *b, int n)
{
lbfgsfloatval_t tmp, max = -1.0;
for (int i = 0; i < n; i++)
{
tmp = sqrt((a[i] - b[i])*(a[i] - b[i]));
max = tmp>max?tmp:max;
}
return max;
}
class TEST_FUNC
{
public:
TEST_FUNC();
virtual ~TEST_FUNC();
static lbfgsfloatval_t _Func(void *instance, const lbfgsfloatval_t *x, lbfgsfloatval_t *g,
const int n, const lbfgsfloatval_t step)
{
return reinterpret_cast<TEST_FUNC*>(instance)->Func(x, g, n, step);
}
lbfgsfloatval_t Func(const lbfgsfloatval_t *x, lbfgsfloatval_t *g,
const int n, const lbfgsfloatval_t step);
static int _Progress(void *instance, const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t fx,
const lbfgsfloatval_t xnorm, const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step, const lbfgs_parameter_t param,
int n, int k, int ls)
{
return reinterpret_cast<TEST_FUNC*>(instance)->Progress(x, g, fx, xnorm, gnorm, step, param, n, k, ls);
}
int Progress(const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t fx,
const lbfgsfloatval_t xnorm, const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step, const lbfgs_parameter_t param,
int n, int k, int ls);
static void _Precondition(void *instance, const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t *d,
lbfgsfloatval_t *d_pre, const int n)
{
return reinterpret_cast<TEST_FUNC*>(instance)->Precondition(x, g, d, d_pre, n);
}
void Precondition(const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t *d,
lbfgsfloatval_t *d_pre, const int n);
int Routine();
private:
lbfgsfloatval_t **kernel;
lbfgsfloatval_t *x, *m, *mid, *d;
};
TEST_FUNC::TEST_FUNC()
{
kernel = new lbfgsfloatval_t* [M];
for (size_t i = 0; i < M; i++)
{
kernel[i] = new lbfgsfloatval_t [N];
}
x = new lbfgsfloatval_t [N];
m = new lbfgsfloatval_t [N];
mid = new lbfgsfloatval_t [M];
d = new lbfgsfloatval_t [M];
srand(time(nullptr));
for (size_t i = 0; i < M; i++)
{
for (size_t j = 0; j < N; j++)
{
kernel[i][j] = scalernd(-2.0, 2.0);
}
}
vecrnd(m, 1.0, 2.0, N);
for (size_t i = 0; i < M; i++)
{
d[i] = 0.0;
for (size_t j = 0; j < N; j++)
{
d[i] += kernel[i][j] * m[j];
}
}
}
TEST_FUNC::~TEST_FUNC()
{
for (size_t i = 0; i < N; i++)
{
delete[] kernel[i];
}
delete[] kernel;
delete[] x;
delete[] m;
delete[] mid;
delete[] d;
}
lbfgsfloatval_t TEST_FUNC::Func(const lbfgsfloatval_t *x, lbfgsfloatval_t *g,
const int n, const lbfgsfloatval_t step)
{
for (size_t i = 0; i < M; i++)
{
mid[i] = 0.0;
for (size_t j = 0; j < N; j++)
{
mid[i] += kernel[i][j] * x[j];
}
mid[i] -= d[i];
}
lbfgsfloatval_t fx = 0;
for (size_t i = 0; i < N; i++)
{
fx += mid[i]*mid[i];
}
for (size_t j = 0; j < N; j++)
{
g[j] = 0.0;
for (size_t i = 0; i < M; i++)
{
g[j] += kernel[i][j]*mid[i];
}
}
return fx;
}
int TEST_FUNC::Progress(const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t fx,
const lbfgsfloatval_t xnorm, const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step, const lbfgs_parameter_t param,
int n, int k, int ls)
{
clog << "\riteration times: " << k << " fx = " << fx << " gnorm/xnorm = " << gnorm/(xnorm>1.0?xnorm:1.0);
return 0;
}
void TEST_FUNC::Precondition(const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t *d,
lbfgsfloatval_t *d_pre, const int n)
{
for (size_t j = 0; j < N; j++)
{
d_pre[j] = 0.0;
for (size_t i = 0; i < M; i++)
{
d_pre[j] += kernel[i][j]*kernel[i][j];
}
d_pre[j] = d[j]/d_pre[j];
}
return;
}
int TEST_FUNC::Routine()
{
lbfgsfloatval_t fx;
lbfgs_parameter_t self_para;
lbfgs_parameter_init(&self_para);
self_para.epsilon = 1e-7;
self_para.linesearch = LBFGS_LINESEARCH_BACKTRACKING_ARMIJO_QUAD;
self_para.ftol = 1e-3;
int ret = lbfgs(N, x, &fx, _Func, _Progress, this, &self_para, _Precondition);
clog << endl << "L-BFGS optimization terminated with status: " << lbfgs_strerror(ret) << endl;
clog << "Maximal difference = " << max_diff(x, m, N) << endl;
return ret;
}
int main(int argc, char const *argv[])
{
TEST_FUNC test;
test.Routine();
return 0;
}