参考博客:
Linux | Ubuntu 20.04安装ipopt和cppAD | 安装全流程+报错解决
1 Ipopt安装
源码安装
(1)安装依赖
sudo apt-get install gcc g++ gfortran git patch wget pkg-config liblapack-dev libmetis-dev libblas-dev
(2)创建一个存放所有跟Ipopt相关的文件夹,便于管理
mkdir ~/Ipopt_pkg
cd Ipopt_pkg
(3)安装ASL
git clone https://github.com/coin-or-tools/ThirdParty-ASL.git
cd ThirdParty-ASL
sudo ./get.ASL
sudo ./configure
sudo make
sudo make install
cd ..
(4)安装HSL
git clone https://github.com/coin-or-tools/ThirdParty-HSL.git
cd ThirdParty-HSL
# 接下来需要下载coinhsl文件,并解压到ThirdParty-HSL目录下
下载coinhsl文件,并解压到ThirdParty-HSL目录下
在ThirdParty-HSL目录下,执行以下命令
sudo ./configure
sudo make
sudo make install
cd ..
(5)安装MUMPS
git clone https://github.com/coin-or-tools/ThirdParty-Mumps.git
cd ThirdParty-Mumps
sudo ./get.Mumps
sudo ./configure
sudo make
sudo make install
cd ..
(6)安装Ipopt
git clone https://github.com/coin-or/Ipopt.git
cd Ipopt
mkdir build
cd build
sudo ../configure
sudo make
sudo make test
sudo make install
(7)完善环境
cd /usr/local/include
sudo cp coin-or coin -r
sudo ln -s /usr/local/lib/libcoinmumps.so.3 /usr/lib/libcoinmumps.so.3
sudo ln -s /usr/local/lib/libcoinhsl.so.2 /usr/lib/libcoinhsl.so.2
sudo ln -s /usr/local/lib/libipopt.so.3 /usr/lib/libipopt.so.3
2 Ipopt测试
进入 IPOPT 源码文件夹如下位置,用官方例子测试
cd Ipopt/build/examples/Cpp_example
sudo make
./cpp_example
出现以下界面安装成功
******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
Ipopt is released as open source code under the Eclipse Public License (EPL).
For more information visit https://github.com/coin-or/Ipopt
******************************************************************************
This is Ipopt version 3.14.14, running with linear solver ma27.
Number of nonzeros in equality constraint Jacobian...: 2
Number of nonzeros in inequality constraint Jacobian.: 0
Number of nonzeros in Lagrangian Hessian.............: 2
Total number of variables............................: 2
variables with only lower bounds: 0
variables with lower and upper bounds: 1
variables with only upper bounds: 0
Total number of equality constraints.................: 1
Total number of inequality constraints...............: 0
inequality constraints with only lower bounds: 0
inequality constraints with lower and upper bounds: 0
inequality constraints with only upper bounds: 0
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 -2.5000000e-01 7.50e-01 5.00e-01 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 -1.8981454e+00 6.12e-01 1.55e+00 -1.0 1.72e+00 0.0 6.27e-01 5.10e-01f 1
2 -3.6781503e+00 1.32e-03 1.60e-01 -1.0 5.40e-01 - 1.00e+00 1.00e+00f 1
3 -3.9900218e+00 1.67e-03 1.22e-02 -1.7 7.98e-02 - 1.00e+00 9.99e-01f 1
4 -3.9998554e+00 1.56e-07 3.88e-06 -3.8 2.46e-03 - 1.00e+00 1.00e+00h 1
5 -3.9999982e+00 3.16e-10 2.54e-09 -5.7 3.57e-05 - 1.00e+00 1.00e+00h 1
6 -4.0000001e+00 5.28e-14 4.23e-13 -8.6 4.60e-07 - 1.00e+00 1.00e+00h 1
Number of Iterations....: 6
(scaled) (unscaled)
Objective...............: -4.0000000774945192e+00 -4.0000000774945192e+00
Dual infeasibility......: 4.2277292777725961e-13 4.2277292777725961e-13
Constraint violation....: 5.2846615972157451e-14 5.2846615972157451e-14
Variable bound violation: 9.6868413290707167e-09 9.6868413290707167e-09
Complementarity.........: 2.5056919964012917e-09 2.5056919964012917e-09
Overall NLP error.......: 2.5056919964012917e-09 2.5056919964012917e-09
Number of objective function evaluations = 7
Number of objective gradient evaluations = 7
Number of equality constraint evaluations = 7
Number of inequality constraint evaluations = 0
Number of equality constraint Jacobian evaluations = 7
Number of inequality constraint Jacobian evaluations = 0
Number of Lagrangian Hessian evaluations = 6
Total seconds in IPOPT = 0.001
EXIT: Optimal Solution Found.
*** The problem solved in 6 iterations!
*** The final value of the objective function is -4.
3 CppAD
3.1 安装
命令行安装:
sudo apt-get install cppad
3.2 CppAD测试
CppAD_demo.cpp
# include <iostream> // standard input/output
# include <vector> // standard vector
# include <cppad/cppad.hpp> // the CppAD package
namespace { // begin the empty namespace
// define the function Poly(a, x) = a[0] + a[1]*x[1] + ... + a[k-1]*x[k-1]
template <class Type>
Type Poly(const CPPAD_TESTVECTOR(double) &a, const Type &x)
{ size_t k = a.size();
Type y = 0.; // initialize summation
Type x_i = 1.; // initialize x^i
for(size_t i = 0; i < k; i++)
{ y += a[i] * x_i; // y = y + a_i * x^i
x_i *= x; // x_i = x_i * x
}
return y;
}
}
// main program
int main(void)
{ using CppAD::AD; // use AD as abbreviation for CppAD::AD
using std::vector; // use vector as abbreviation for std::vector
// vector of polynomial coefficients
size_t k = 5; // number of polynomial coefficients
CPPAD_TESTVECTOR(double) a(k); // vector of polynomial coefficients
for(size_t i = 0; i < k; i++)
a[i] = 1.; // value of polynomial coefficients
// domain space vector
size_t n = 1; // number of domain space variables
vector< AD<double> > ax(n); // vector of domain space variables
ax[0] = 3.; // value at which function is recorded
// declare independent variables and start recording operation sequence
CppAD::Independent(ax);
// range space vector
size_t m = 1; // number of ranges space variables
vector< AD<double> > ay(m); // vector of ranges space variables
ay[0] = Poly(a, ax[0]); // record operations that compute ay[0]
// store operation sequence in f: X -> Y and stop recording
CppAD::ADFun<double> f(ax, ay);
// compute derivative using operation sequence stored in f
vector<double> jac(m * n); // Jacobian of f (m by n matrix)
vector<double> x(n); // domain space vector
x[0] = 3.; // argument value for computing derivative
jac = f.Jacobian(x); // Jacobian for operation sequence
// print the results
std::cout << "f'(3) computed by CppAD = " << jac[0] << std::endl;
// check if the derivative is correct
int error_code;
if( jac[0] == 142. )
error_code = 0; // return code for correct case
else error_code = 1; // return code for incorrect case
return error_code;
}
CMakeList.txt
cmake_minimum_required(VERSION 3.02)
project(testCPP)
set(CMAKE_CXX_STANDARD 14)
add_executable(CppAD_demo src/CppAD_demo.cpp)
出现以下命令测试成功
f'(3) computed by CppAD = 142
4 测试Ipopt与CppAD
IPOPT+cppad求解优化问题例子(C++)
利用CppAD与Ipopt求解以下非线性规划问题
cppad_ipopt_demo.cpp
#include <iostream>
// 头文件,用于使用 CppAD 和 Ipopt 库
#include <cppad/ipopt/solve.hpp>
using namespace std;
// 定义仿函数,用于计算目标函数和约束
namespace {
using CppAD::AD;
class FG_eval {
public:
// CPPAD_TESTVECTOR 是 CppAD 中定义的一个宏,用于创建 AD 向量。
typedef CPPAD_TESTVECTOR(AD<double>) ADvector;
// operator() 函数实现了仿函数的功能,计算目标函数和约束。在这里,目标函数和约束的数量都是 3 个。
void operator()(ADvector& fg, const ADvector& x)
{
// assert 语句用于确保 fg 向量和 x 向量的大小分别为 3 和 4。
assert(fg.size() == 3);
assert(x.size() == 4);
// variables
// 将决策变量从 x 向量中提取出来,分别赋值给 x1、x2、x3 和 x4
AD<double> x1 = x[0];
AD<double> x2 = x[1];
AD<double> x3 = x[2];
AD<double> x4 = x[3];
// f(x) objective function
fg[0] = x1 * x4 * (x1 + x2 + x3) + x3;
// constraints
fg[1] = x1 * x2 * x3 * x4;
fg[2] = x1 * x1 + x2 * x2 + x3 * x3 + x4 * x4;
return;
}
};
}
// get_started 函数是程序的入口。它初始化了问题的参数,包括变量的数量(nx),约束的数量(ng),以及初始条件(x0 向量)。
bool get_started(void)
{
bool ok = true;
size_t i;
typedef CPPAD_TESTVECTOR(double) Dvector;
size_t nx = 4; // 决策变量个数
size_t ng = 2; // 决策约束个数
Dvector x0(nx); // 变量初始值
x0[0] = 1.0;
x0[1] = 5.0;
x0[2] = 5.0;
x0[3] = 1.0;
// 决策变量界限设置
Dvector xl(nx), xu(nx);
for(i = 0; i < nx; i++)
{
xl[i] = 1.0;
xu[i] = 5.0;
}
Dvector gl(ng), gu(ng);
gl[0] = 25.0; gu[0] = 1.0e19;
gl[1] = 40.0; gu[1] = 40.0;//等式约束描述为等式约束
// 创建了 FG_eval 类的实例,用于计算目标函数和约束
FG_eval fg_eval;
// options
string options;// 字符串,用于存储 Ipopt 求解器的选项。
// turn off any printing
options += "Integer print_level 0\n";
options += "String sb yes\n";
// maximum iterations
// 设置最大迭代次数为 10。这是一个控制求解器运行时间的参数。
//如果求解器达到了最大迭代次数而没有找到满足收敛标准的解,求解器将提前退出。
options += "Integer max_iter 10\n";
//approximate accuracy in first order necessary conditions;
// see Mathematical Programming, Volume 106, Number 1,
// Pages 25-57, Equation (6)
//设置收敛容许误差。这个参数控制求解器停止迭代的条件,
//当当前迭代的优化进度足够小(小于 tol)时,求解器将停止运行。
options += "Numeric tol 1e-6\n";
//derivative tesing
options += "String derivative_test second-order\n";
// maximum amount of random pertubation; e.g.,
// when evaluation finite diff
//置数值微分的随机扰动半径。在进行数值微分时,为了计算梯度和黑塞矩阵,
//可能会对变量进行小幅度的扰动。这个选项设置了扰动的最大半径。将其设置为 0 表示关闭数值微分。
options += "Numeric point_perturbation_radius 0.\n";
// 将结果存储在 solution
CppAD::ipopt::solve_result<Dvector> solution; // solution
// 求解问题
CppAD::ipopt::solve<Dvector, FG_eval>(options, x0, xl, xu, gl, gu, fg_eval, solution); // solve the problem
cout<<"solution: "<<solution.x<<endl;
//
//check some of the solution values
//
//进行最优解的检查,确保求解器成功并且最优解在预期范围内。
ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;
//预期的最优解。这是在已知问题的情况下提前计算的一个参考解。
double check_x[] = {1.000000, 4.743000, 3.82115, 1.379408};
double check_zl[] = {1.087871, 0., 0., 0. };
double check_zu[] = {0., 0., 0., 0. };
//相对容差和绝对容差。在进行近似相等性比较时,通常会使用相对容差和绝对容差。这两个参数用于定义两个值在多大程度上被认为是相等的。
double rel_tol = 1e-6; // relative tolerance
double abs_tol = 1e-6; // absolute tolerance
//对最优解的逐个分量进行检查。使用 CppAD::NearEqual 函数进行比较
//如果解与预期解在相对容差和绝对容差内足够接近,则 ok 变量会保持为 true,否则为 false。
for(i = 0; i < nx; i++)
{
ok &= CppAD::NearEqual(
check_x[i], solution.x[i], rel_tol, abs_tol);
ok &= CppAD::NearEqual(
check_zl[i], solution.zl[i], rel_tol, abs_tol);
ok &= CppAD::NearEqual(
check_zu[i], solution.zu[i], rel_tol, abs_tol);
}
return ok;
}
int main()
{
cout << "CppAD : Hello World Demo!" << endl;
get_started();
return 0;
}
CMakeList.txt
cmake_minimum_required(VERSION 3.0.2)
project(cppa)
find_package(catkin REQUIRED COMPONENTS
roscpp
)
set(CMAKE_CXX_STANDARD 14)
include_directories(/usr/local/include)
link_directories(/usr/local/lib)
add_executable(CppAD_demo src/CppAD_demo.cpp)
target_link_libraries(CppAD_demo ipopt)
其中:
include_directories(/usr/local/include)
link_directories(/usr/local/lib)
很重要,因为不加这个,找不到ipopt,会出现段错误
输出以下结果测试成功:
CppAD : Hello World Demo!
solution: { 1, 4.743, 3.82115, 1.37941 }
文章详细介绍了CppAD和Ipopt求解器的安装