github: https://github.com/devernay/cminpack 主页: http://devernay.github.io/cminpack/ 使用手册: http://devernay.github.io/cminpack/man.htmlhtml
从github中clone下来源文件,进入目录后新建build,使用cmake对上一层目录内容进行编译configure->generate。git
命令行不熟练可使用cmake-gui指令,须要选中examples选项才会对样例进行编译。github
完成后进入build/examples目录,执行make命令,能够看到已经生成可执行文件,运行其中任意程序进行测试。 算法
再进入到build/cmake目录,执行make命令和make install命令,将cminpack.pc安装到指定目录(个人电脑上安装到了/usr/local/lib64/pkgconfig),最后将这个目录经过/etc/profile添加到pkg的路径当中(别忘了source运行一下)。 在命令行中输入pkg-config opencv –libs –cflags
,若是可以显示路径则成功。 [NOTE] 我对pkg-config的使用并非很了解,是模仿着opencv进行配置的。数组
[NOTE] 所以本身对CMake使用还很不熟练,所以找机会对CMakeList.txt进行学习。缓存
# 由于Markdown没有支持CMakeList.txt的高亮,所以用Makefile的高亮将就一下。 # The name of our project is "CMINPACK". CMakeLists files in this project can # refer to the root source directory of the project as ${CMINPACK_SOURCE_DIR} and # to the root binary directory of the project as ${CMINPACK_BINARY_DIR}. # CMINPACK_SOURCE_DIR: CMinpack源代码的根目录 # CMINPACK_BINARY_DIR: CMinpack二进制文件的根目录 # 要求的最小CMake版本号 cmake_minimum_required (VERSION 2.6) # 项目名称:CMINPACK project (CMINPACK) # PROJECT_NAME: CMINPACK # PROJECT_NAME_LOWER: cminpack string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) # include其余CMake命令 # 在cminpack_utils.cmake这个文件中定义了GET_OS_INFO和DISSECT_VERSION两个宏指令,后面进行详细介绍。 include(${PROJECT_SOURCE_DIR}/cmake/cminpack_utils.cmake) # Set version and OS-specific settings # CACHE: 缓存到本地文件 set(CMINPACK_VERSION 1.3.6 CACHE STRING "CMinpack version") set(CMINPACK_SOVERSION 1 CACHE STRING "CMinpack API version") # 在cminpack_utils.cmake中定义的两个宏 DISSECT_VERSION() GET_OS_INFO() # Add an "uninstall" target # CONFIGURE_FILE: 让普通文件也能使用CMake中的变量 # 输入文件: uninstall_target.cmake.in # 输出文件: uninstall_target.cmake # IMMEDIATE: 暂时没找到意思 # @ONLY: 限制只替换被@VAR@引用的变量(${VAR}格式的变量不会被替换) CONFIGURE_FILE ("${PROJECT_SOURCE_DIR}/cmake/uninstall_target.cmake.in" "${PROJECT_BINARY_DIR}/uninstall_target.cmake" IMMEDIATE @ONLY) # ADD_CUSTOM_TARGET: 增长一个没有输出的目标,使得它老是被构建 # CMAKE_COMMAND: 指向CMake可执行文件的完整路径 ADD_CUSTOM_TARGET (uninstall "${CMAKE_COMMAND}" -P "${PROJECT_BINARY_DIR}/uninstall_target.cmake") # 须要注意,ctest指望在build目录下找到测试文件。 enable_testing() if (OS_LINUX OR ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") option (USE_FPIC "Use the -fPIC compiler flag." ON) else (OS_LINUX) option (USE_FPIC "Use the -fPIC compiler flag." OFF) endif (OS_LINUX) # 生成SHARED库的选项 option (BUILD_SHARED_LIBS "Build shared libraries instead of static." OFF) if (BUILD_SHARED_LIBS) message (STATUS "Building shared libraries.") else () message (STATUS "Building static libraries.") set(CMAKE_RELEASE_POSTFIX _s) set(CMAKE_RELWITHDEBINFO_POSTFIX _s) set(CMAKE_DEBUG_POSTFIX _s) set(CMAKE_MINSIZEREL_POSTFIX _s) if(WIN32) add_definitions(-DCMINPACK_NO_DLL) endif(WIN32) endif () option(USE_BLAS "Compile cminpack using a blas library if possible" ON) #set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/../build) # 添加头文件目录 if(NOT "${CMAKE_PREFIX_PATH}" STREQUAL "") include_directories(${CMAKE_PREFIX_PATH}/include) endif() # cminpack_srcs: 源代码文件 set (cminpack_srcs cminpack.h cminpackP.h chkder.c enorm.c hybrd1.c hybrj.c lmdif1.c lmstr1.c qrfac.c r1updt.c dogleg.c fdjac1.c hybrd.c lmder1.c lmdif.c lmstr.c qrsolv.c rwupdt.c dpmpar.c fdjac2.c hybrj1.c lmder.c lmpar.c qform.c r1mpyq.c covar.c covar1.c minpack.h chkder_.c enorm_.c hybrd1_.c hybrj_.c lmdif1_.c lmstr1_.c qrfac_.c r1updt_.c dogleg_.c fdjac1_.c hybrd_.c lmder1_.c lmdif_.c lmstr_.c qrsolv_.c rwupdt_.c dpmpar_.c fdjac2_.c hybrj1_.c lmder_.c lmpar_.c qform_.c r1mpyq_.c covar_.c ) # cminpack_hdrs: 头文件 set (cminpack_hdrs cminpack.h minpack.h) # 添加一个名为cminpack的库 add_library (cminpack ${cminpack_srcs}) if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") TARGET_LINK_LIBRARIES(cminpack m) endif() # Link with a BLAS library if requested if (USE_BLAS) if (NOT BUILD_SHARED_LIBS) set(BLA_STATIC True) endif() find_package(BLAS) if (BLAS_FOUND) target_link_libraries(cminpack PUBLIC ${BLAS_LIBRARIES}) set_target_properties(cminpack PROPERTIES LINK_FLAGS "${BLAS_LINKER_FLAGS}") target_compile_definitions(cminpack PUBLIC -DUSE_CBLAS) endif() endif() # install: 为工程生成安装规则 # TARGETS版本的install命令 install (TARGETS cminpack # 模块库 LIBRARY DESTINATION ${CMINPACK_LIB_INSTALL_DIR} COMPONENT library # 静态连接的库文件 ARCHIVE DESTINATION ${CMINPACK_LIB_INSTALL_DIR} COMPONENT library # 动态库 RUNTIME DESTINATION bin COMPONENT library) # FILES版本的install命令 # 以相对路径方式给出的文件名是相对当前源代码路径而言的,默认具备OWNER_WRITE, OWNER_READ, GROUP_READ和WORLD_READ权限 install (FILES ${cminpack_hdrs} DESTINATION ${CMINPACK_INCLUDE_INSTALL_DIR} COMPONENT cminpack_hdrs) if (USE_FPIC AND NOT BUILD_SHARED_LIBS) set_target_properties (cminpack PROPERTIES COMPILE_FLAGS -fPIC) endif () set_target_properties(cminpack PROPERTIES VERSION ${CMINPACK_VERSION} SOVERSION ${CMINPACK_SOVERSION}) # add_subdirectory: 添加子项目 add_subdirectory (cmake) add_subdirectory (examples)
# 获取系统信息,设置安装位置 macro(GET_OS_INFO) # string(REGEX MATCH 正则表达 输出变量 ) string(REGEX MATCH "Linux" OS_LINUX ${CMAKE_SYSTEM_NAME}) string(REGEX MATCH "BSD" OS_BSD ${CMAKE_SYSTEM_NAME}) if(WIN32) set(OS_WIN TRUE) endif(WIN32) if(NOT DEFINED CMINPACK_LIB_INSTALL_DIR) set(CMINPACK_LIB_INSTALL_DIR "lib") if(OS_LINUX) if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") set(CMINPACK_LIB_INSTALL_DIR "lib64") else(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") set(CMINPACK_LIB_INSTALL_DIR "lib") endif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") message (STATUS "Operating system is Linux") elseif(OS_BSD) message (STATUS "Operating system is BSD") elseif(OS_WIN) message (STATUS "Operating system is Windows") else(OS_LINUX) message (STATUS "Operating system is generic Unix") endif(OS_LINUX) endif(NOT DEFINED CMINPACK_LIB_INSTALL_DIR) # 好比/usr/local/include/cminpack-1 set(CMINPACK_INCLUDE_INSTALL_DIR "include/${PROJECT_NAME_LOWER}-${CMINPACK_MAJOR_VERSION}") endmacro(GET_OS_INFO) # 解剖CMinpack版本号 macro(DISSECT_VERSION) # Find version components string(REGEX REPLACE "^([0-9]+).*" "\\1" CMINPACK_MAJOR_VERSION "${CMINPACK_VERSION}") string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" CMINPACK_MINOR_VERSION "${CMINPACK_VERSION}") string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" CMINPACK_REVISION_VERSION ${CMINPACK_VERSION}) string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.[0-9]+(.*)" "\\1" CMINPACK_CANDIDATE_VERSION ${CMINPACK_VERSION}) endmacro(DISSECT_VERSION)
# 可选项 # option (选项名 "选项注释" 默认内容) option (BUILD_EXAMPLES "Build the examples and tests." ON) option (BUILD_EXAMPLES_FORTRAN "Build the FORTRAN examples and tests." OFF) if (BUILD_EXAMPLES) # Make sure the compiler can find include files from our cminpack library. include_directories (${CMINPACK_SOURCE_DIR}) # Make sure the linker can find the cminpack library once it is built. link_directories (${CMINPACK_BINARY_DIR}) # 设置变量内容 # set(变量 内容) set (FPGM tchkder thybrd thybrd1 thybrj thybrj1 tlmder tlmder1 tlmdif tlmdif1 tlmstr tlmstr1) set (CPGM ${FPGM} tfdjac2) # cmpfile: 用于一行行地比较两个文件的异同 # cmpfiles could be used by runtest.cmake... for now it's unused # add_executable(可执行文件名称 源文件) add_executable (cmpfiles cmpfiles.c) # inspired by http://www.netlib.org/clapack/clapack-3.2.1-CMAKE/TESTING/CMakeLists.txt # except that here we have to compare the output to a reference # 测试部分跳过不看 macro(add_minpack_test testname reference) set(TEST_OUTPUT "${CMINPACK_BINARY_DIR}/examples/${testname}.out") set(TEST_REFERENCE "${CMINPACK_SOURCE_DIR}/examples/ref/${reference}.ref") get_target_property(TEST_LOC ${testname} LOCATION) add_test(${testname} "${CMAKE_COMMAND}" -DTEST=${TEST_LOC} -DOUTPUT=${TEST_OUTPUT} -DREFERENCE=${TEST_REFERENCE} -DINTDIR=${CMAKE_CFG_INTDIR} -P "${CMINPACK_SOURCE_DIR}/examples/runtest.cmake") endmacro(add_minpack_test) # 遍历处理每个目标文件 foreach (source ${CPGM}) add_executable (${source}_ ${source}_.c) target_link_libraries (${source}_ cminpack) if (OS_LINUX) target_link_libraries (${source}_ m) endif (OS_LINUX) add_minpack_test(${source}_ ${source}c) add_executable (${source}c ${source}c.c) target_link_libraries (${source}c cminpack) if (OS_LINUX) target_link_libraries (${source}c m) endif (OS_LINUX) add_minpack_test(${source}c ${source}c) endforeach(source) endif (BUILD_EXAMPLES) # FORTRAN部分跳过不看
根据咱们阅读给出的测试样例的CMake相关文件,咱们能够开始动手写本身的第一个CMinpack程序。 新建目录,目录下放着咱们要运行的使用了CMinpack的程序my-cminpack-demo.c。 开始编写CMakeLists.txt文件,首先提取出咱们须要的内容:app
project(my-cminpack-demo) cmake_minimum_required (VERSION 2.6) include_directories (${CMINPACK_SOURCE_DIR}) link_directories (${CMINPACK_BINARY_DIR}) add_executable (my-cminpack-demo my-cminpack-demo.c) target_link_libraries (my-cminpack-demo cminpack) if (OS_LINUX) target_link_libraries (my-cminpack-demo m) endif (OS_LINUX)
而后新建build目录,在build目录下运行cmake ..
发现会跳出找不到sqrt函数的错误,这个咱们可以一会儿联想到是Linux系统下没有链接到m库文件的缘由。虽然我不知道这个判断为何没法执行,可是咱们已知在Linux环境下,把它去掉。 获得最终的CMakeLists.txt:less
project(my-cminpack-demo) cmake_minimum_required (VERSION 2.6) include_directories (${CMINPACK_SOURCE_DIR}) link_directories (${CMINPACK_BINARY_DIR}) add_executable (my-cminpack-demo my-cminpack-demo.c) target_link_libraries (my-cminpack-demo cminpack) target_link_libraries (my-cminpack-demo m)
虽然咱们make获得可执行文件,运行后查看结果(图中我使用了tlmdif_.c做为测试) ide
lmdif
, lmdif1_
- 最小化非线性函数平方和
include <minpack.h> void lmdif1_(void (*fcn)(int *m, int *n, double *x, double *fvec, int *iflag), int *m, int *n, double *x, double *fvec, double *tol, int *info, int *iwa, double *wa, int *lwa); void lmdif_(void (*fcn)(int *m, int *n, double *x, double *fvec, int *iflag), int *m, int *n, double *x, double *fvec, double *ftol, double *xtol, double *gtol, int *maxfev, double *epsfcn, double *diag, int *mode, double *factor, int *nprint, int *info, int *nfev, double *fjac, int *ldfjac, int *ipvt, double *qtf, double *wa1, double *wa2, double *wa3, double *wa4 );
lmdif_
的目的是最小化m个n元非线性方程的平方和,使用的方法是LM算法的改进。用户须要提供计算方程的子程序。Jacobian矩阵会经过一个前向差分(forward-difference)近似计算获得。 lmdif1_
是相同的目的,可是调用方法更简单一些。
这些函数是经过FORTRAN写的,若是从C调用,须要记住如下几点:
void fcn(int m, int n, double *x, double *fvec, int *iflag) { /* 计算函数在x点的值,经过fvec返回。*/ }
iflag的值不能被fcn所修改,除非用户想要终止lmdif
/lmdif1_
。在这个例子中iflag设置为负整数。
m:函数个数; n:变量个数(n<=m) x:长度为n的数组,设置为初始的估计解向量。输出的时候x内容为最终估计的解向量。 fvec:输出长度为m的数组,内容为最终输出x计算获得的函数解。
tol:做为输入,非负数。用于函数终止的条件判断:
info:做为输出。若是用户终止了函数的执行,info将被设置为iflag的值(负数)(详细见fcn的描述),不然,info的值以下几种状况:
iwa:长度n的工做数组; wa:长度lwa的工做数组; lwa:做为输入,整数,不能小于mn+5n+m; [NOTE] 这三个输入我也不知道做用,从样例来看不须要初始化。
暂时不用这部分,跳过。
/* lmdif1 例子. */ #include <stdio.h> #include <math.h> #include <assert.h> #include <minpack.h> #define real __minpack_real__ // 用户自定义的函数f() // real -> __cminpack_real__ -> 浮点数(double) void fcn(const int *m, const int *n, const real *x, real *fvec, int *iflag); int main() { int j, m, n, info, lwa, iwa[3], one=1; real tol, fnorm, x[3], fvec[15], wa[75]; // 函数个数15; 变量数3 m = 15; n = 3; // 初始位置作粗略估计 // 1.e0 = 1.0e0 = 1.0 x[0] = 1.e0; x[1] = 1.e0; x[2] = 1.e0; // 为何要设置75? lwa = 75; /* set tol to the square root of the machine precision. unless high precision solutions are required, this is the recommended setting. */ // (建议打印一下看值是多少) tol = sqrt(__minpack_func__(dpmpar)(&one)); // 须要注意指针 __minpack_func__(lmdif1)(&fcn, &m, &n, x, fvec, &tol, &info, iwa, wa, &lwa); // 最终的2范数(即平方和开根号) fnorm = __minpack_func__(enorm)(&m, fvec); printf(" final l2 norm of the residuals%15.7g\n\n", (double)fnorm); printf(" exit parameter %10i\n\n", info); printf(" final approximate solution\n"); for (j=1; j<=n; j++) { printf("%s%15.7g", j%3==1?"\n ":"", (double)x[j-1]); } printf("\n"); return 0; } // The problem is to determine the values of x(1), x(2), and x(3) // which provide the best fit (in the least squares sense) of // x(1) + u(i)/(v(i)*x(2) + w(i)*x(3)), i = 1, 15 // to the data // y = (0.14,0.18,0.22,0.25,0.29,0.32,0.35,0.39, // 0.37,0.58,0.73,0.96,1.34,2.10,4.39), // where u(i) = i, v(i) = 16 - i, and w(i) = min(u(i),v(i)). The // i-th component of FVEC is thus defined by // y(i) - (x(1) + u(i)/(v(i)*x(2) + w(i)*x(3))). void fcn(const int *m, const int *n, const real *x, real *fvec, int *iflag) { /* function fcn for lmdif1 example */ int i; real tmp1,tmp2,tmp3; // 实际的y值 real y[15]={1.4e-1,1.8e-1,2.2e-1,2.5e-1,2.9e-1,3.2e-1,3.5e-1,3.9e-1, 3.7e-1,5.8e-1,7.3e-1,9.6e-1,1.34e0,2.1e0,4.39e0}; assert(*m == 15 && *n == 3); if (*iflag == 0) { /* insert print statements here when nprint is positive. */ /* if the nprint parameter to lmder is positive, the function is called every nprint iterations with iflag=0, so that the function may perform special operations, such as printing residuals. */ // 这段没有很看懂,在??状况下打印信息 return; } /* compute residuals */ for (i=0; i<15; i++) { tmp1 = i+1; tmp2 = 15 - i; tmp3 = tmp1; if (i >= 8) { tmp3 = tmp2; } fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3)); } }
[NOTE] 其余内容有待更新
原文出处:https://www.cnblogs.com/bemfoo/p/11203993.html