Ipopt(Interior Point OPTimizer)
是求解大規(guī)模非線性最優(yōu)化問題的求解軟件??梢郧蠼馊缦滦问降淖顑?yōu)化問題的(局部)最優(yōu)解。
m
i
n
?
x
∈
R
n
???
f
(
x
)
s
.
t
.
g
L
≤
g
(
x
)
≤
g
U
x
L
≤
x
≤
x
U
(0)
\underbrace{min}_ {x \in R?} \, \, \, f(x) \\ s.t. g_L ≤ g(x) ≤ g_U \\ x_L ≤ x ≤ x_U \tag{0}
x∈Rn
min??f(x)s.t.gL?≤g(x)≤gU?xL?≤x≤xU?(0)
其中,
f
(
x
)
:
R
n
→
R
f(x): R^n \rightarrow R
f(x):Rn→R是優(yōu)化目標函數(shù),
g
(
x
)
:
R
n
→
R
m
g(x):R^n \rightarrow R^m
g(x):Rn→Rm是約束函數(shù),
f
(
x
)
,
g
(
x
)
f(x),g(x)
f(x),g(x)可以是非線性和非凸的,但是需要是二階微分連續(xù)的。
為了求解最優(yōu)化問題,Ipopt
需要更多的信息,如下:
- 優(yōu)化問題的維度
- 優(yōu)化變量 x x x的數(shù)目;
- 約束函數(shù) g ( x ) g(x) g(x)的數(shù)目;
- 優(yōu)化變量的邊界
- 優(yōu)化變量 x x x的邊界;
- 約束函數(shù) g ( x ) g(x) g(x)的邊界;
- 優(yōu)化問題的初始迭代點:
- 優(yōu)化變量 x x x的初始值;
- 拉格朗日乘子的初始值(僅僅是在
warm start
的時候需要);
- 優(yōu)化問題的數(shù)據(jù)結構(
Structure
):- 約束函數(shù) g ( x ) g(x) g(x)的雅可比矩陣的非零元素的數(shù)目;
- 拉格朗日函數(shù)的黑森矩陣的非零元素的數(shù)目;
- 約束函數(shù)
g
(
x
)
g(x)
g(x)的雅可比稀疏矩陣的非零元素的行索引和列索引(
sparsity structure,row and column indices of each of the nonzero entries
); - 拉格朗日函數(shù)的黑森稀疏矩陣的非零元素的行索引和列索引(
sparsity structure,row and column indices of each of the nonzero entries
);
- 優(yōu)化問題函數(shù)的值:
- 優(yōu)化目標函數(shù) f ( x ) f(x) f(x);
- 優(yōu)化目標函數(shù)的梯度函數(shù) c c c;
- 約束函數(shù) g ( x ) g(x) g(x);
- 約束函數(shù)的雅可比矩陣 ? g ( x ) T \nabla g(x) ^T ?g(x)T;
- 拉格朗日函數(shù)的黑森矩陣
σ
f
?
2
f
(
x
)
+
∑
i
=
1
m
λ
i
?
2
g
i
(
x
)
\sigma_f \nabla ^2 f(x) + \sum_{i=1}^m \lambda_i \nabla ^2 g_i(x)
σf??2f(x)+∑i=1m?λi??2gi?(x),如果使用擬牛頓法(
quasi-Newton options
)則不需要此矩陣;
優(yōu)化問題的維度和邊界約束可以直接獲得,并且來自于問題定義。初始迭代點會影響優(yōu)化問題的是否收斂或者是否收斂到(局部)最優(yōu)解,不同的初始值可能會導致收斂到不同的局部最優(yōu)解。計算微分矩陣(雅可比矩陣和黑森矩陣)可能有一點復雜,Ipopt
需要提供約束函數(shù)的雅可比矩陣和拉格朗日函數(shù)的黑森矩陣的非零元素以及他們所在的行索引和列索引,并且標準接口是下三角矩陣(黑森矩陣是對稱矩陣)。矩陣的非零元素確定后,在整個求解過程中是不可變的,因此,非零元素不可以僅僅包含在初始值條件下,還需要包括在求解過程中會不為零的元素。
1. Example
f = x 1 x 4 ( x 1 + x 2 + x 3 ) + x 3 s . t . ?????? x 1 x 2 x 3 x 4 ≥ 25 x 1 2 + x 2 2 + x 3 2 + x 4 2 = 40 1 ≤ x 1 , x 2 , x 3 , x 4 ≤ 5 x 0 = ( 1 , 5 , 5 , 1 ) (1-1) f = x_1 x_4 (x_1 + x_2 + x_3) + x_3 \\ s.t. \,\,\,\,\,\, x_1 x_2 x_3 x_4 \geq 25 \\ x^2_1 + x^2_2 + x^2_3 + x^2_4 = 40 \\ 1 \leq x_1, x_2, x_3, x_4 \leq 5 \\ x_0 = (1,5,5,1) \tag{1-1} f=x1?x4?(x1?+x2?+x3?)+x3?s.t.x1?x2?x3?x4?≥25x12?+x22?+x32?+x42?=401≤x1?,x2?,x3?,x4?≤5x0?=(1,5,5,1)(1-1)
可以得到優(yōu)化目標的梯度為:
?
f
(
x
)
=
[
x
1
x
4
+
x
4
(
x
1
+
x
2
+
x
3
)
x
1
x
4
x
1
x
4
+
1
x
1
(
x
1
+
x
2
+
x
3
)
]
(1-2)
\nabla f(x) = \begin{bmatrix} x_1 x_4 + x_4(x_1 + x_2 + x_3) \\ x_1 x_4 \\ x_1 x_4 + 1 \\ x_1 (x_1 + x_2 + x_3) \end{bmatrix} \tag{1-2}
?f(x)=?
??x1?x4?+x4?(x1?+x2?+x3?)x1?x4?x1?x4?+1x1?(x1?+x2?+x3?)??
??(1-2)
可以得到約束函數(shù)的雅可比矩陣為:
?
g
(
x
)
=
[
x
2
x
3
x
4
x
1
x
3
x
4
x
1
x
2
x
4
x
1
x
2
x
3
2
x
1
2
x
2
2
x
3
2
x
4
]
(1-3)
\nabla g(x) = \begin{bmatrix} x_2 x_3 x_4 & x_1 x_3 x_4 & x_1 x_2 x_4 & x_1 x_2 x_3 \\ 2 x_1 & 2 x_2 & 2 x_3 & 2 x_4 \end{bmatrix} \tag{1-3}
?g(x)=[x2?x3?x4?2x1??x1?x3?x4?2x2??x1?x2?x4?2x3??x1?x2?x3?2x4??](1-3)
需要計算拉格朗日函數(shù)的黑森矩陣,如果使用擬牛頓法來近似二階微分,則不需要提供黑森矩陣。但是黑森矩陣可以是計算有更好的魯棒性和更快的收斂速度。NLP
的拉格朗日函數(shù)定義為
f
(
x
)
+
g
(
x
)
T
λ
f(x) + g(x)^T \lambda
f(x)+g(x)Tλ,黑森矩陣定義為
?
2
f
(
x
)
+
∑
i
=
1
m
λ
i
?
2
g
i
(
x
)
\nabla ^2 f(x) + \sum_{i=1}^m \lambda_i \nabla ^2 g_i(x)
?2f(x)+∑i=1m?λi??2gi?(x),然而在Ipopt
中引入
σ
f
\sigma_f
σf?使Ipopt
可以分別確定優(yōu)化目標函數(shù)和約束函數(shù)的黑森矩陣,因此Ipopt
的黑森矩陣為
σ
f
?
2
f
(
x
)
+
∑
i
=
1
m
λ
i
?
2
g
i
(
x
)
\sigma_f \nabla ^2 f(x) + \sum_{i=1}^m \lambda_i \nabla ^2 g_i(x)
σf??2f(x)+∑i=1m?λi??2gi?(x)??梢缘玫絻?yōu)化問題
(
1
?
1
)
(1-1)
(1?1)的黑森矩陣為:
σ
f
[
2
x
4
x
4
x
4
2
x
1
+
x
2
+
x
3
x
4
0
0
x
1
x
4
0
0
x
1
2
x
1
+
x
2
+
x
3
x
1
x
1
0
]
+
λ
1
[
0
x
3
x
4
x
2
x
4
x
2
x
3
x
3
x
4
0
x
1
x
4
x
1
x
3
x
2
x
4
x
1
x
4
0
x
1
x
2
x
2
x
3
x
1
x
3
x
1
x
2
0
]
+
λ
2
[
2
0
0
0
0
2
0
0
0
0
2
0
0
0
0
2
]
(1-4)
\sigma_f \begin{bmatrix} 2 x_4 & x_4 & x_4 & 2 x_1 + x_2 + x_3 \\ x_4 & 0 & 0 & x_1 \\ x_4 & 0 & 0 & x_1 \\ 2 x_1 + x_2 + x_3 & x_1 & x_1 & 0 \end{bmatrix}+ \lambda_1 \begin{bmatrix} 0 & x_3 x_4 & x_2 x_4 & x_2 x_3 \\ x_3 x_4 & 0 & x_1 x_4 & x_1 x_3 \\ x_2 x_4 & x_1 x_4 & 0 & x_1 x_2 \\ x_2 x_3 & x_1 x_3 & x_1 x_2 & 0 \end{bmatrix}+ \lambda_2 \begin{bmatrix} 2 & 0 & 0 & 0 \\ 0 & 2 & 0 & 0 \\ 0 & 0 & 2 & 0 \\ 0 & 0 & 0 & 2 \end{bmatrix} \tag{1-4}
σf??
??2x4?x4?x4?2x1?+x2?+x3??x4?00x1??x4?00x1??2x1?+x2?+x3?x1?x1?0??
??+λ1??
??0x3?x4?x2?x4?x2?x3??x3?x4?0x1?x4?x1?x3??x2?x4?x1?x4?0x1?x2??x2?x3?x1?x3?x1?x2?0??
??+λ2??
??2000?0200?0020?0002??
??(1-4)
其中,第一項是優(yōu)化目標函數(shù)的黑森矩陣,第二項和第三項是約束函數(shù)的黑森矩陣,
λ
1
,
λ
2
\lambda_1,\lambda_2
λ1?,λ2?是約束函數(shù)的拉格朗日乘子。
2. C++ Interface
需要繼承純虛基類Ipopt::TNLP
來編寫自己的求解類,并且需要重載
9
9
9個Ipopt::TNLP
基類的虛函數(shù),Ipopt
通過Ipopt::IpoptApplication
類來求解最優(yōu)化問題。
2.1 Ipopt::TNLP::get_nlp_info
virtual bool get_nlp_info(
Index& n,
Index& m,
Index& nnz_jac_g,
Index& nnz_h_lag,
IndexStyleEnum& index_style
) = 0;
Ipopt
使用這個函數(shù)來確定數(shù)組的內(nèi)存分配,這里如果發(fā)生問題,會引起內(nèi)存泄漏等問題,很難去debug。
-
n
:優(yōu)化變量 x x x的數(shù)目; -
m
:約束函數(shù) g ( x ) g(x) g(x)的數(shù)目; -
nnz_jac_g
:雅可比矩陣非零元素的數(shù)目; -
nnz_h_lag
:黑森矩陣非零元素的數(shù)目; -
index_style
:稀疏矩陣的索引使用C
語言風格(從 0 0 0開始),還是使用Fortran
語言風格(從 1 1 1開始);
上述例子中有 4 4 4個優(yōu)化變量, 2 2 2個約束函數(shù),雅可比矩陣中的非零元素個數(shù)為 8 8 8,黑森矩陣中非零元素的個數(shù)為 16 16 16,由于是對稱矩陣,因此下三角矩陣中非零元素個數(shù)為 10 10 10。
// returns the size of the problem
bool HS071_NLP::get_nlp_info(
Index& n,
Index& m,
Index& nnz_jac_g,
Index& nnz_h_lag,
IndexStyleEnum& index_style
)
{
// The problem described in HS071_NLP.hpp has 4 variables, x[0] through x[3]
n = 4;
// one equality constraint and one inequality constraint
m = 2;
// in this example the jacobian is dense and contains 8 nonzeros
nnz_jac_g = 8;
// the Hessian is also dense and has 16 total nonzeros, but we
// only need the lower left corner (since it is symmetric)
nnz_h_lag = 10;
// use the C style indexing (0-based)
index_style = TNLP::C_STYLE;
return true;
}
2.2 Ipopt::TNLP::get_bounds_info
virtual bool get_bounds_info(
Index n,
Number* x_l,
Number* x_u,
Index m,
Number* g_l,
Number* g_u
) = 0;
Ipopt
使用這個函數(shù)來確定優(yōu)化變量
x
x
x的邊界和約束函數(shù)
g
(
x
)
g(x)
g(x)的邊界。
-
n
:優(yōu)化變量 x x x的數(shù)目; -
x_l
:優(yōu)化變量 x x x的下邊界,數(shù)組; -
x_u
:優(yōu)化變量 x x x的上邊界,數(shù)組; -
m
:約束函數(shù) g ( x ) g(x) g(x)的數(shù)目; -
g_l
:約束函數(shù) g ( x ) g(x) g(x)的下邊界,數(shù)組; -
g_u
:約束函數(shù) g ( x ) g(x) g(x)的上邊界,數(shù)組;
在Ipopt
中默認設置邊界值需要在
(
?
1
0
9
,
1
0
9
)
(-10^9, 10^9)
(?109,109)范圍內(nèi),當不在此范圍時,則認為是無窮大或者無窮小。
// returns the variable bounds
bool HS071_NLP::get_bounds_info(
Index n,
Number* x_l,
Number* x_u,
Index m,
Number* g_l,
Number* g_u
)
{
// here, the n and m we gave IPOPT in get_nlp_info are passed back to us.
// If desired, we could assert to make sure they are what we think they are.
assert(n == 4);
assert(m == 2);
// the variables have lower bounds of 1
for( Index i = 0; i < 4; i++ )
{
x_l[i] = 1.0;
}
// the variables have upper bounds of 5
for( Index i = 0; i < 4; i++ )
{
x_u[i] = 5.0;
}
// the first constraint g1 has a lower bound of 25
g_l[0] = 25;
// the first constraint g1 has NO upper bound, here we set it to 2e19.
// Ipopt interprets any number greater than nlp_upper_bound_inf as
// infinity. The default value of nlp_upper_bound_inf and nlp_lower_bound_inf
// is 1e19 and can be changed through ipopt options.
g_u[0] = 2e19;
// the second constraint g2 is an equality constraint, so we set the
// upper and lower bound to the same value
g_l[1] = g_u[1] = 40.0;
return true;
}
2.3 Ipopt::TNLP::get_starting_point
virtual bool get_starting_point(
Index n,
bool init_x,
Number* x,
bool init_z,
Number* z_L,
Number* z_U,
Index m,
bool init_lambda,
Number* lambda
) = 0;
Ipopt
使用這個函數(shù)來確定迭代優(yōu)化的起點。
-
n
:優(yōu)化變量 x x x的數(shù)目; -
init_x
:如果是ture
,則需要提供優(yōu)化變量 x x x的初始值; -
x
:優(yōu)化變量 x x x的初始值;
其他為dual variables
的初始值,一般不用設置。在Ipopt
中默認是需要設置
x
x
x的初始值。
// returns the initial point for the problem
bool HS071_NLP::get_starting_point(
Index n,
bool init_x,
Number* x,
bool init_z,
Number* z_L,
Number* z_U,
Index m,
bool init_lambda,
Number* lambda
)
{
// Here, we assume we only have starting values for x, if you code
// your own NLP, you can provide starting values for the dual variables
// if you wish
assert(init_x == true);
assert(init_z == false);
assert(init_lambda == false);
// initialize to the given starting point
x[0] = 1.0;
x[1] = 5.0;
x[2] = 5.0;
x[3] = 1.0;
return true;
}
2.4 Ipopt::TNLP::eval_f
virtual bool eval_f(
Index n,
const Number* x,
bool new_x,
Number& obj_value
) = 0;
Ipopt
使用這個函數(shù)來確定優(yōu)化目標函數(shù)。
-
n
:優(yōu)化變量 x x x的數(shù)目; -
x
:優(yōu)化變量 x x x的值,用來計算 f ( x ) f(x) f(x); -
new_x
:在此之前調(diào)用的eval_*
函數(shù)是否有錯誤發(fā)生,可以忽略; -
obj_value
: f ( x ) f(x) f(x);
// returns the value of the objective function
bool HS071_NLP::eval_f(
Index n,
const Number* x,
bool new_x,
Number& obj_value
)
{
assert(n == 4);
obj_value = x[0] * x[3] * (x[0] + x[1] + x[2]) + x[2];
return true;
}
2.5 Ipopt::TNLP::eval_grad_f
virtual bool eval_grad_f(
Index n,
const Number* x,
bool new_x,
Number* grad_f
) = 0;
Ipopt
使用這個函數(shù)來確定優(yōu)化目標函數(shù)的梯度。
-
n
:優(yōu)化變量 x x x的數(shù)目; -
x
:優(yōu)化變量 x x x的值,用來計算 ? f ( x ) \nabla f(x) ?f(x); -
new_x
:在此之前調(diào)用的eval_*
函數(shù)是否有錯誤發(fā)生,可以忽略; -
obj_value
: ? f ( x ) \nabla f(x) ?f(x),數(shù)組的大小和 x x x的數(shù)組大小一致;
// return the gradient of the objective function grad_{x} f(x)
bool HS071_NLP::eval_grad_f(
Index n,
const Number* x,
bool new_x,
Number* grad_f
)
{
assert(n == 4);
grad_f[0] = x[0] * x[3] + x[3] * (x[0] + x[1] + x[2]);
grad_f[1] = x[0] * x[3];
grad_f[2] = x[0] * x[3] + 1;
grad_f[3] = x[0] * (x[0] + x[1] + x[2]);
return true;
}
2.6 Ipopt::TNLP::eval_g
virtual bool eval_g(
Index n,
const Number* x,
bool new_x,
Index m,
Number* g
) = 0;
Ipopt
使用這個函數(shù)來確定約束函數(shù)
g
(
x
)
g(x)
g(x)。
-
n
:優(yōu)化變量 x x x的數(shù)目; -
x
:優(yōu)化變量 x x x的值,用來計算 ? f ( x ) \nabla f(x) ?f(x); -
new_x
:在此之前調(diào)用的eval_*
函數(shù)是否有錯誤發(fā)生,可以忽略; -
m
:約束函數(shù) g ( x ) g(x) g(x)的數(shù)目; - g: g ( x ) g(x) g(x),數(shù)組的大小和 m m m一致;
// return the value of the constraints: g(x)
bool HS071_NLP::eval_g(
Index n,
const Number* x,
bool new_x,
Index m,
Number* g
)
{
assert(n == 4);
assert(m == 2);
g[0] = x[0] * x[1] * x[2] * x[3];
g[1] = x[0] * x[0] + x[1] * x[1] + x[2] * x[2] + x[3] * x[3];
return true;
}
2.7 Ipopt::TNLP::eval_jac_g
virtual bool eval_jac_g(
Index n,
const Number* x,
bool new_x,
Index m,
Index nele_jac,
Index* iRow,
Index* jCol,
Number* values
) = 0;
Ipopt
使用這個函數(shù)來確定約束函數(shù)
g
(
x
)
g(x)
g(x)的雅可比矩陣的非零元素的值,以及其在稀疏矩陣中的行索引值和列索引值。雅可比矩陣中的第
i
i
i行和第
j
j
j列的元素值是
g
i
(
x
)
g_i(x)
gi?(x)對
x
j
x_j
xj?的導數(shù)。
-
n
:優(yōu)化變量 x x x的數(shù)目; -
x
:優(yōu)化變量 x x x的值,用來計算 ? g ( x ) T \nabla g(x)^T ?g(x)T; -
new_x
:在此之前調(diào)用的eval_*
函數(shù)是否有錯誤發(fā)生,可以忽略; -
m
:約束函數(shù) g ( x ) g(x) g(x)的數(shù)目; -
nele_jac
:雅可比矩陣非零元素的數(shù)目; -
iRow
:存儲雅可比矩陣非零元素在矩陣中的行索引值,如果是C
語言風格,雅可比矩陣索引值從 0 0 0開始; -
jCol
:存儲雅可比矩陣非零元素在矩陣中的列索引值,如果是C
語言風格,雅可比矩陣索引值從 0 0 0開始; -
values
:存儲雅可比矩陣中的非零元素;
需要注意的是:①iRow
、jCol
和values
三個數(shù)組的大小是一致的,并且其儲存的值應該和雅可比矩陣非零元素的行索引值、列索引值和非零元素值相對應;②數(shù)組iRow
和jCol
只需要被填寫一次,即第一次調(diào)用此函數(shù)時填寫iRow
和jCol
,第一次調(diào)用時x
和values
都是null
,當Ipopt
需要values
的值時,傳遞iRow
和jCol
將會是null
,此時對values
的值進行填寫。
// return the structure or values of the Jacobian
bool HS071_NLP::eval_jac_g(
Index n,
const Number* x,
bool new_x,
Index m,
Index nele_jac,
Index* iRow,
Index* jCol,
Number* values
)
{
assert(n == 4);
assert(m == 2);
if( values == NULL )
{
// return the structure of the Jacobian
// this particular Jacobian is dense
iRow[0] = 0;
jCol[0] = 0;
iRow[1] = 0;
jCol[1] = 1;
iRow[2] = 0;
jCol[2] = 2;
iRow[3] = 0;
jCol[3] = 3;
iRow[4] = 1;
jCol[4] = 0;
iRow[5] = 1;
jCol[5] = 1;
iRow[6] = 1;
jCol[6] = 2;
iRow[7] = 1;
jCol[7] = 3;
}
else
{
// return the values of the Jacobian of the constraints
values[0] = x[1] * x[2] * x[3]; // 0,0
values[1] = x[0] * x[2] * x[3]; // 0,1
values[2] = x[0] * x[1] * x[3]; // 0,2
values[3] = x[0] * x[1] * x[2]; // 0,3
values[4] = 2 * x[0]; // 1,0
values[5] = 2 * x[1]; // 1,1
values[6] = 2 * x[2]; // 1,2
values[7] = 2 * x[3]; // 1,3
}
return true;
}
2.8 Ipopt::TNLP::eval_h
virtual bool eval_h(
Index n,
const Number* x,
bool new_x,
Number obj_factor,
Index m,
const Number* lambda,
bool new_lambda,
Index nele_hess,
Index* iRow,
Index* jCol,
Number* values
)
Ipopt
使用這個函數(shù)來確定拉格朗日函數(shù)黑森矩陣的非零元素的值,以及其在稀疏矩陣中的行索引值和列索引值。
-
n
:優(yōu)化變量 x x x的數(shù)目; -
x
:優(yōu)化變量 x x x的值,用來計算 ? g ( x ) T \nabla g(x)^T ?g(x)T; -
new_x
:在此之前調(diào)用的eval_*
函數(shù)是否有錯誤發(fā)生,可以忽略; -
obj_factor
: σ f \sigma_f σf?; -
m
:約束函數(shù) g ( x ) g(x) g(x)的數(shù)目; -
lambda
:拉格朗日乘子 λ \lambda λ; -
new_lambda
:如果之前調(diào)用的函數(shù)使用相同的 λ \lambda λ則為false
,一般忽略; -
nele_hess
:黑森矩陣非零元素的個數(shù)(下三角矩陣); -
iRow
:存儲黑森矩陣非零元素在矩陣中的行索引值,如果是C
語言風格,黑森矩陣索引值從 0 0 0開始; -
jCol
:存儲黑森矩陣非零元素在矩陣中的列索引值,如果是C
語言風格,黑森矩陣索引值從 0 0 0開始; -
values
:存儲黑森矩陣中的非零元素的值;
需要注意的是:①iRow
、jCol
和values
三個數(shù)組的大小是一致的,并且其儲存的值應該和黑森矩陣非零元素的行索引值、列索引值和非零元素值相對應;②數(shù)組iRow
和jCol
只需要被填寫一次,即第一次調(diào)用此函數(shù)時填寫iRow
和jCol
,第一次調(diào)用時x
、lambda
和values
都是null
,當Ipopt
需要values
的值時,傳遞iRow
和jCol
將會是null
,此時對values
的值進行填寫;③由于黑森矩陣是對稱陣,Ipopt
使用下三角矩陣;④Ipopt
默認是需要黑森矩陣的,當使用擬牛頓法時,則不需要黑森矩陣。
在此例中,黑森矩陣是稠密的,但是仍然使用稀疏矩陣來表示。
//return the structure or values of the Hessian
bool HS071_NLP::eval_h(
Index n,
const Number* x,
bool new_x,
Number obj_factor,
Index m,
const Number* lambda,
bool new_lambda,
Index nele_hess,
Index* iRow,
Index* jCol,
Number* values
)
{
assert(n == 4);
assert(m == 2);
if( values == NULL )
{
// return the structure. This is a symmetric matrix, fill the lower left
// triangle only.
// the hessian for this problem is actually dense
Index idx = 0;
for( Index row = 0; row < 4; row++ )
{
for( Index col = 0; col <= row; col++ )
{
iRow[idx] = row;
jCol[idx] = col;
idx++;
}
}
assert(idx == nele_hess);
}
else
{
// return the values. This is a symmetric matrix, fill the lower left
// triangle only
// fill the objective portion
values[0] = obj_factor * (2 * x[3]); // 0,0
values[1] = obj_factor * (x[3]); // 1,0
values[2] = 0.; // 1,1
values[3] = obj_factor * (x[3]); // 2,0
values[4] = 0.; // 2,1
values[5] = 0.; // 2,2
values[6] = obj_factor * (2 * x[0] + x[1] + x[2]); // 3,0
values[7] = obj_factor * (x[0]); // 3,1
values[8] = obj_factor * (x[0]); // 3,2
values[9] = 0.; // 3,3
// add the portion for the first constraint
values[1] += lambda[0] * (x[2] * x[3]); // 1,0
values[3] += lambda[0] * (x[1] * x[3]); // 2,0
values[4] += lambda[0] * (x[0] * x[3]); // 2,1
values[6] += lambda[0] * (x[1] * x[2]); // 3,0
values[7] += lambda[0] * (x[0] * x[2]); // 3,1
values[8] += lambda[0] * (x[0] * x[1]); // 3,2
// add the portion for the second constraint
values[0] += lambda[1] * 2; // 0,0
values[2] += lambda[1] * 2; // 1,1
values[5] += lambda[1] * 2; // 2,2
values[9] += lambda[1] * 2; // 3,3
}
return true;
}
2.9 Ipopt::TNLP::finalize_solution
virtual void finalize_solution(
SolverReturn status,
Index n,
const Number* x,
const Number* z_L,
const Number* z_U,
Index m,
const Number* g,
const Number* lambda,
Number obj_value,
const IpoptData* ip_data,
IpoptCalculatedQuantities* ip_cq
) = 0;
Ipopt
使用這個函數(shù)來得到最優(yōu)化問題的求解結果,對其重要的值進行介紹。文章來源:http://www.zghlxwxcb.cn/news/detail-808294.html
-
status
:求解器的狀態(tài);-
SUCCESS
:在滿足收斂條件的情況下,找到局部最優(yōu)解; -
MAXITER_EXCEEDED
:超出最大迭代次數(shù); -
CPUTIME_EXCEEDED
:超出最大求解時間; -
STOP_AT_ACCEPTABLE_POINT
:求解收斂在某點,不滿足期望的容差,但是在可接受范圍內(nèi); -
LOCAL_INFEASIBILITY
:在可行域內(nèi)找不到最優(yōu)解,一般是由于bounds
和約束設置不合理導致的;
-
-
x
:優(yōu)化變量 x x x的局部最優(yōu)解的值;
void HS071_NLP::finalize_solution(
SolverReturn status,
Index n,
const Number* x,
const Number* z_L,
const Number* z_U,
Index m,
const Number* g,
const Number* lambda,
Number obj_value,
const IpoptData* ip_data,
IpoptCalculatedQuantities* ip_cq
)
{
// here is where we would store the solution to variables, or write to a file, etc
// so we could use the solution.
// For this example, we write the solution to the console
std::cout << std::endl << std::endl << "Solution of the primal variables, x" << std::endl;
for( Index i = 0; i < n; i++ )
{
std::cout << "x[" << i << "] = " << x[i] << std::endl;
}
std::cout << std::endl << std::endl << "Solution of the bound multipliers, z_L and z_U" << std::endl;
for( Index i = 0; i < n; i++ )
{
std::cout << "z_L[" << i << "] = " << z_L[i] << std::endl;
}
for( Index i = 0; i < n; i++ )
{
std::cout << "z_U[" << i << "] = " << z_U[i] << std::endl;
}
std::cout << std::endl << std::endl << "Objective value" << std::endl;
std::cout << "f(x*) = " << obj_value << std::endl;
std::cout << std::endl << "Final value of the constraints:" << std::endl;
for( Index i = 0; i < m; i++ )
{
std::cout << "g(" << i << ") = " << g[i] << std::endl;
}
}
2.10 main function
上述對Ipopt::TNLP
的函數(shù)進行了重載,但是需要編寫調(diào)用Ipopt
的函數(shù)來執(zhí)行求解。文章來源地址http://www.zghlxwxcb.cn/news/detail-808294.html
#include "IpIpoptApplication.hpp"
#include "hs071_nlp.hpp"
#include <iostream>
using namespace Ipopt;
int main(
int /*argv*/,
char** /*argc*/
)
{
// Create a new instance of your nlp
// (use a SmartPtr, not raw)
SmartPtr<TNLP> mynlp = new HS071_NLP();
// Create a new instance of IpoptApplication
// (use a SmartPtr, not raw)
// We are using the factory, since this allows us to compile this
// example with an Ipopt Windows DLL
SmartPtr<IpoptApplication> app = IpoptApplicationFactory();
// Change some options
// Note: The following choices are only examples, they might not be
// suitable for your optimization problem.
app->Options()->SetNumericValue("tol", 3.82e-6);
app->Options()->SetStringValue("mu_strategy", "adaptive");
app->Options()->SetStringValue("output_file", "ipopt.out");
// The following overwrites the default name (ipopt.opt) of the options file
// app->Options()->SetStringValue("option_file_name", "hs071.opt");
// Initialize the IpoptApplication and process the options
ApplicationReturnStatus status;
status = app->Initialize();
if( status != Solve_Succeeded )
{
std::cout << std::endl << std::endl << "*** Error during initialization!" << std::endl;
return (int) status;
}
// Ask Ipopt to solve the problem
status = app->OptimizeTNLP(mynlp);
if( status == Solve_Succeeded )
{
std::cout << std::endl << std::endl << "*** The problem solved!" << std::endl;
}
else
{
std::cout << std::endl << std::endl << "*** The problem FAILED!" << std::endl;
}
// As the SmartPtrs go out of scope, the reference count
// will be decremented and the objects will automatically
// be deleted.
return (int) status;
}
到了這里,關于非線性最優(yōu)化問題求解器Ipopt介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!