国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

詳細介紹如何使用Ipopt非線性求解器求解帶約束的最優(yōu)化問題

這篇具有很好參考價值的文章主要介紹了詳細介紹如何使用Ipopt非線性求解器求解帶約束的最優(yōu)化問題。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

?? 本文中將詳細介紹如何使用Ipopt非線性求解器求解帶約束的最優(yōu)化問題,結(jié)合給出的帶約束的最優(yōu)化問題示例,給出相應(yīng)的完整的C++程序,并給出詳細的解釋和注釋,以及編譯規(guī)則等

?? 一、Ipopt庫的安裝和測試

?? 本部分內(nèi)容在之前的文章《Ubuntu20.04安裝Ipopt的流程介紹及報錯解決方法(親測簡單有效)》中已經(jīng)詳細介紹過了,鏈接如下:

?? https://blog.csdn.net/qq_44339029/article/details/133679131


?? 二、使用Ipopt非線性求解器求解帶約束的最優(yōu)化問題的程序示例


?? 0、明確要求解的帶約束的最優(yōu)化問題

?? 首先,我們來看一個簡單的帶約束的最優(yōu)化問題,其包含兩個不等式約束和1個等式約束,詳情如下:

?? f = ( x 1 ? 10.24 ) 2 + 5.21 x 2 + 9.9 ( x 3 ? x 4 ) 2 f=(x_1-10.24)^2+5.21x_2+9.9(x_3-x_4)^2 f=(x1??10.24)2+5.21x2?+9.9(x3??x4?)2

?? g 1 : 2 ≤ x 3 ? x 4 ≤ 10 g 2 : 2.99 ≤ x 2 ≤ 100 g 3 : x 2 = x 4 \begin{aligned}g_1 & : & 2\leq x_3-x_4\leq10\\ g_2 & : & 2.99\leq x_2\leq100\\ g_3 & : & x_2=x_4\end{aligned} g1?g2?g3??:::?2x3??x4?102.99x2?100x2?=x4??

?? 其中 x 1 x_1 x1?、 x 2 x_2 x2?、 x 3 x_3 x3?、 x 4 x_4 x4?的取值范圍均為0~100,易知使得上述目標函數(shù) f f f取值最小的解為:10.24、2.99、4.99、2.99。

?? 下面介紹,如何編程使用Ipopt非線性求解器求解該問題


?? 1. 引入頭文件和命名空間:

#include <iostream>
#include <cassert>
#include <cppad/ipopt/solve.hpp>
using CppAD::AD;

?? 引入必要的C++頭文件,包括iostream(用于輸入輸出),cassert(用于C風格的assert)以及cppad/ipopt/solve.hpp(用于Ipopt求解器和CppAD庫的接口)。然后在一個匿名的命名空間中引入了AD類型,這是CppAD庫中用于自動微分(Automatic Differentiation)的數(shù)據(jù)類型。

?? 2. 定義FG_eval類:

namespace {
    class FG_eval {
    public:
        typedef CPPAD_TESTVECTOR(AD<double>) ADvector;
        
        void operator()(ADvector& fg, const ADvector& x) {
            // ...
        }
    };
}

?? 在匿名命名空間中,定義一個FG_eval類,用于計算目標函數(shù)和約束條件的值。這個類也是調(diào)用使用CppAD和Ipopt庫所需的最重要的接口,這個類中的operator()函數(shù)是用于計算問題的目標函數(shù)和約束條件的核心部分。它接受兩個向量:fg用于存儲目標函數(shù)值和約束條件值,x用于存儲優(yōu)化變量。

?? 3. 定義operator()函數(shù):

?? 接下來,我們根據(jù)第0步中明確的目標函數(shù)及約束條件來編寫核心的operator函數(shù),示例如下:

void FG_eval::operator()(ADvector& fg, const ADvector& x) {
    assert(fg.size() == 4);
    assert(x.size() == 4);

    AD<double> x1 = x[0];
    AD<double> x2 = x[1];
    AD<double> x3 = x[2];
    AD<double> x4 = x[3];

    fg[0] = (x1 - 10.24) * (x1 - 10.24) + 5.21 * x2 + 9.9 * (x3 - x4) * (x3 - x4);
    fg[1] = x3 - x4;
    fg[2] = x2;
    fg[3] = x2 - x4;
    
    // 打印計算結(jié)果
    std::cout << "fg[0]:" << fg[0] << std::endl;
    std::cout << "fg[1]:" << fg[1] << std::endl;
    std::cout << "fg[2]:" << fg[2] << std::endl;
    std::cout << "fg[3]:" << fg[3] << std::endl;
}

?? operator()函數(shù)接受fgx向量,然后根據(jù)問題的定義計算目標函數(shù)和約束條件的值,并將它們存儲在fg向量中。同時,它也打印出這些值, 其中fg[0]即為目標函數(shù)表達式、fg[1]、fg[2]、fg[3]中依次對應(yīng)了第0步中設(shè)定的三個約束,不等式約束直接寫即可,等式約束的等式左右兩邊同時減去右邊的項,使等式右邊變?yōu)?。

?? 4. 定義主函數(shù)get_started(該函數(shù)名字可任?。?/font>

?? 定義一個主函數(shù),設(shè)定自變量的初始值,以及自變量和約束的上下限,設(shè)定和提供調(diào)用Ipopt非線性求解器求解所需要的變量,然后調(diào)用求解器進行求解,并進行驗證等操作,程序示例如下:

bool get_started(void)
{	bool ok = true;
	size_t i;
	typedef CPPAD_TESTVECTOR( double ) Dvector;
	size_t nx = 4;
	size_t ng = 3;
	Dvector xi(nx);
	xi[0] = 10.0;
	xi[1] = 5.0;
	xi[2] = 5.0;
	xi[3] = 100.0;
	Dvector xl(nx), xu(nx);
	for(i = 0; i < nx; i++)
	{	xl[i] = 0;
		xu[i] = 100;
	}

	Dvector gl(ng), gu(ng);
	gl[0] = 2;     gu[0] = 10;
	gl[1] = 2.99;  gu[1] = 100;
	gl[2] = 0;     gu[2] = 0;

	FG_eval fg_eval;
	std::string options;
	options += "Integer print_level  0\n";
	options += "String  sb           yes\n";
	options += "Integer max_iter     10\n";
	options += "Numeric tol          1e-6\n";
	options += "String  derivative_test            second-order\n";
	options += "Numeric point_perturbation_radius  0.\n";
	CppAD::ipopt::solve_result<Dvector> solution;
	CppAD::ipopt::solve<Dvector, FG_eval>(
		options, xi, xl, xu, gl, gu, fg_eval, solution
	);
	
	ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;
	double check_x[]  = { 10.24, 2.99, 4.99, 2.99 }; 
	double rel_tol    = 1e-6;  // relative tolerance
	double abs_tol    = 1e-6;  // absolute tolerance
	for(i = 0; i < nx; i++)
	{		
		ok &= CppAD::NearEqual(
			check_x[i],  solution.x[i],   rel_tol, abs_tol     
		); 
        std::cout << "x[" << i << "] = " << solution.x[i] << std::endl;
	}
	return ok;
}

?? 以下是程序的詳細解釋:

?? (1). bool get_started(void):程序邏輯流程的主要函數(shù),get_started函數(shù)定義了問題的基本參數(shù),如變量數(shù)量、約束數(shù)量、變量的初始值,以及變量和約束的上下界。然后,它創(chuàng)建了一個FG_eval對象來計算目標函數(shù)和約束條件,設(shè)置了Ipopt求解器的選項,并最終調(diào)用求解器來解決問題。

?? (2). bool ok = true;:定義一個布爾變量 ok,用于表示問題是否成功求解。一開始將其初始化為 true。

?? (3). 類型別名 Dvector:通過 typedef CPPAD_TESTVECTOR(double) Dvector; 定義了一個 Dvector 類型,它是CppAD庫中的向量類型,用于存儲雙精度(double)數(shù)值。

?? (4). size_t nx = 4;:定義一個 size_t 類型的變量 nx,表示問題中獨立變量(自變量)的數(shù)量,即問題的變量維度。在這個示例中,有4個獨立的自變量。

?? (5). size_t ng = 3;:定義一個 size_t 類型的變量 ng,表示問題中的約束數(shù)量,即約束的維度。在這個示例中,有3個約束條件。

?? (6). 創(chuàng)建 Dvector 向量 xi:用于存儲問題的獨立變量(自變量)。這個向量有4個元素,對應(yīng)于4個自變量。

?? (7). 設(shè)置初始猜測值 xi:為 xi 向量中的每個元素分別賦初值,為檢驗算法性能,這里設(shè)定了一個較差的初始值。

   - `xi[0] = 10.0;`
   - `xi[1] = 5.0;`
   - `xi[2] = 5.0;`
   - `xi[3] = 100.0;`

?? (8). 定義變量和約束條件的上下界:

?? - 創(chuàng)建 Dvector 向量 xlxu,它們分別表示變量的下界和上界,并根據(jù)第0步中的設(shè)定的自變量的取值范圍0~100進行設(shè)定

?? - 創(chuàng)建 Dvector 向量 glgu,它們分別表示約束條件的下界和上界,并根據(jù)第0步中,三個約束的進行設(shè)定,對于前兩個不等式約束,直接設(shè)定即可,第三個等式約束,即 x 2 ? x 4 = 0 x_2-x_4=0 x2??x4?=0,因此,上下限均設(shè)為0即可。

?? (9). 創(chuàng)建 FG_eval 類的對象 fg_evalFG_eval 即我們第二步中設(shè)定的類,用于計算目標函數(shù)和約束條件的值。這是問題的目標函數(shù)和約束條件的具體定義。

?? (10). 創(chuàng)建字符串 options:用于存儲Ipopt求解器的選項,包括設(shè)置輸出級別、最大迭代次數(shù)、收斂容差等,詳情如下所示:

    - `options += "Integer print_level  0\n";`:將輸出級別設(shè)置為0,以關(guān)閉求解器的詳細輸出,只打印關(guān)鍵信息。
    - `options += "String  sb           yes\n";`:使用平衡約束優(yōu)化方法。
    - `options += "Integer max_iter     10\n";`:設(shè)置最大迭代次數(shù)為10次。
    - `options += "Numeric tol          1e-6\n";`:設(shè)置迭代停止的收斂容差為1e-6。
    - `options += "String  derivative_test            second-order\n";`:啟用二階導數(shù)測試,用于檢查目標函數(shù)和約束條件的導數(shù)是否正確。
    - `options += "Numeric point_perturbation_radius  0.\n";`:將隨機擾動的半徑設(shè)置為0,表示不使用擾動進行數(shù)值近似求導。

?? (11). 創(chuàng)建 CppAD::ipopt::solve_result<Dvector> solution;:用于存儲求解結(jié)果的對象。

?? (12). 調(diào)用 CppAD::ipopt::solve 函數(shù):使用Ipopt求解器解決非線性規(guī)劃問題。傳遞了問題選項、獨立變量的初始值、變量的上下界、約束條件的上下界、問題的定義(fg_eval 對象),以及存儲結(jié)果的 solution 對象。

?? (13). 檢查求解器的狀態(tài):如果狀態(tài)為成功(success),則將 ok 變量保持為真,表示問題已成功求解。

?? 注:下面的第(14)~(16)部分,是為了驗證求解是否正確,為非必要步驟

?? (14) 創(chuàng)建 check_x 數(shù)組:包含問題的精確解。這些值是問題的已知精確解。

?? (15). 設(shè)置相對容差和絕對容差的閾值:這些值用于控制驗證解的精度。

?? (16). 遍歷問題中的每個變量,進行解的驗證:使用 CppAD::NearEqual 函數(shù)來比較問題的解與精確解是否足夠接近。如果它們的差距在相對容差和絕對容差的范圍內(nèi),ok 變量將保持為真,并打印每個變量的解。

?? (17).返回 ok 變量:表示問題是否成功求解。

??

?? 5. C++主函數(shù)main

int main(void) {
    std::cout << "===== Ipopt with CppAD Testing =====" << std::endl;
    bool result = get_started();
    std::cout << "Final checking: " << result << std::endl;
}

?? main函數(shù)是程序的入口點,它簡單地調(diào)用get_started函數(shù)來執(zhí)行非線性規(guī)劃問題的求解,并打印結(jié)果。


?? 6. ☆☆☆帶詳細注釋的完整程序`☆☆☆

# include <iostream>
// C style asserts
# include <cassert>
// 包含Ipopt求解器頭文件
# include <cppad/ipopt/solve.hpp>


// 在一個匿名的命名空間中,引入了一個AD類型,它是CppAD庫中用于自動微分(Automatic Differentiation)的數(shù)據(jù)類型。AD類型可以用來表示變量和函數(shù),使其具備微分能力。
namespace {
	using CppAD::AD;

	class FG_eval {
	public:
		typedef CPPAD_TESTVECTOR( AD<double> ) ADvector;
        // fg: function that evaluates the objective and constraints using the syntax
		// 定義一個函數(shù)運算符,用于計算目標函數(shù)和約束條件的值
		void operator()(ADvector& fg, const ADvector& x)
		{	
			//使用assert來設(shè)定fg和x的大小,以確保它們與問題的維度匹配
			//fg 向量用于存儲目標函數(shù)值和約束條件值,x向量用于存儲優(yōu)化變量
			assert( fg.size() == 4 );
			assert( x.size()  == 4 );

			//  將 x 中的優(yōu)化變量分配給 AD 類型的變量 x1 到 x4。這是在使用C++ Algorithmic Differentiation(CppAD)時定義問題中的獨立變量的方式。
			AD<double> x1 = x[0];
			AD<double> x2 = x[1];
			AD<double> x3 = x[2];
			AD<double> x4 = x[3];
			// 計算目標函數(shù)的值,將其存儲在 fg[0] 中。這里使用了 x1 到 x4 這些 AD 類型的變量,這意味著這個表達式將被自動微分,以便后續(xù)的梯度計算。
			fg[0] = (x1-10.24) * (x1-10.24) + 5.21*x2 + 9.9*(x3-x4)*(x3-x4);
			//  分別計算三個約束條件的值,并將它們存儲在 fg[1] 和 fg[2]、 fg[3]中。
			fg[1] = x3-x4;
			fg[2] = x2;
            fg[3] = x2-x4;
			//
			std::cout << "fg[0]:" << fg[0]<< std::endl;
			std::cout << "fg[1]:" << fg[1]<< std::endl;
			std::cout << "fg[2]:" << fg[2]<< std::endl;
            std::cout << "fg[3]:" << fg[3]<< std::endl;

			return;
		}
	};
}

// 該函數(shù)用于設(shè)置和解決非線性規(guī)劃問題
// 它首先定義了問題的一些基本參數(shù),如變量數(shù)量、約束數(shù)量、變量的初始值、變量和約束的上下界等
// 然后創(chuàng)建一個FG_eval對象用于計算目標函數(shù)和約束條件
// 最后,使用CppAD::ipopt::solve函數(shù)來解決問題,并將結(jié)果存儲在solution中
bool get_started(void)
{	bool ok = true;
	size_t i;
	// 創(chuàng)建了一個類型別名 Dvector,它是CppAD庫中的一個向量類型,用于存儲雙精度(double)數(shù)值。這個向量類型是CppAD庫的一部分,通常用于存儲問題的變量、約束和其他向量。
	typedef CPPAD_TESTVECTOR( double ) Dvector;

	// 聲明了一個 size_t 類型的變量 nx,它表示問題中獨立變量(自變量)的數(shù)量,也就是問題的變量維度。在這個示例中,有4個獨立變量,因此 nx 的值為4。
	size_t nx = 4;
	// 聲明了一個 size_t 類型的變量 ng,它表示問題中的約束數(shù)量,也就是約束的維度。在這個示例中,有3個約束條件,因此 ng 的值為3。
	size_t ng = 3;
	//  創(chuàng)建了一個名為 xi 的 Dvector 類型的向量,用于存儲問題的獨立變量(自變量)。這個向量有4個元素,對應(yīng)于4個自變量。
	Dvector xi(nx);
	// 分別為這4個獨立變量設(shè)置了初始值。這些值將用作問題的初始猜測,作為非線性規(guī)劃求解器的起點。
	xi[0] = 10.0;
	xi[1] = 5.0;
	xi[2] = 5.0;
	xi[3] = 100.0;

	//設(shè)置問題的變量(自變量)和約束條件的上下界(限制條件)。
	Dvector xl(nx), xu(nx);
	for(i = 0; i < nx; i++)
	{	xl[i] = 0;
		xu[i] = 100;
	}

	Dvector gl(ng), gu(ng);
	gl[0] = 2;     gu[0] = 10;
	gl[1] = 2.99;  gu[1] = 100;
	gl[2] = 0;     gu[2] = 0;

	// 創(chuàng)建了 FG_eval 類的對象 fg_eval,用于計算目標函數(shù)和約束條件的值。這是問題的目標函數(shù)和約束條件的具體定義。
	FG_eval fg_eval;

	// 創(chuàng)建了一個字符串 options,用于存儲Ipopt求解器的選項。
	std::string options;
	// 設(shè)置了求解器選項,將 print_level 參數(shù)設(shè)置為0,以關(guān)閉求解器的輸出,即不會在控制臺打印詳細信息,只打印關(guān)鍵信息。
	options += "Integer print_level  0\n";
	//  將 sb 參數(shù)設(shè)置為 "yes",這表示使用平衡約束優(yōu)化方法。
	options += "String  sb           yes\n";
	// 設(shè)置最大迭代次數(shù)為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)
	// 設(shè)置迭代停止的收斂容差為1e-6。
	options += "Numeric tol          1e-6\n";
	//  啟用了二階導數(shù)測試,用于檢查目標函數(shù)和約束條件的導數(shù)是否正確。
	options += "String  derivative_test            second-order\n";
	// maximum amount of random pertubation; e.g.,
	// when evaluation finite diff
	// 將隨機擾動的半徑設(shè)置為0,表示不使用擾動進行數(shù)值近似求導。
	options += "Numeric point_perturbation_radius  0.\n";

	// 創(chuàng)建了一個用于存儲求解結(jié)果的對象 solution,
	CppAD::ipopt::solve_result<Dvector> solution;

	// 調(diào)用了 CppAD::ipopt::solve 函數(shù),用于解決非線性規(guī)劃問題。它傳遞了問題選項、獨立變量的初始值、變量的上下界、約束條件的上下界、問題的定義(fg_eval 對象),以及存儲結(jié)果的 solution 對象。
	CppAD::ipopt::solve<Dvector, FG_eval>(
		options, xi, xl, xu, gl, gu, fg_eval, solution
	);

	//檢查求解器的狀態(tài),如果狀態(tài)為成功(success),則 ok 變量將保持為真。這表示問題已成功求解。
	ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;
	// 創(chuàng)建一個名為 check_x 的數(shù)組,其中包含了問題的精確解。這個數(shù)組中的值是問題的已知精確解。
	double check_x[]  = { 10.24, 2.99, 4.99, 2.99 }; 
	// 設(shè)置了相對容差和絕對容差的閾值。這些值用于控制驗證解的精度。
	double rel_tol    = 1e-6;  // relative tolerance
	double abs_tol    = 1e-6;  // absolute tolerance
	// 遍歷問題中的每個變量,進行解的驗證。
	for(i = 0; i < nx; i++)
	{	
		//使用 CppAD::NearEqual 函數(shù)來比較問題的解 solution.x[i] 與精確解 check_x[i] 是否足夠接近。如果它們的差距在相對容差和絕對容差的范圍內(nèi),ok 變量將保持為真。
		ok &= CppAD::NearEqual(
			check_x[i],  solution.x[i],   rel_tol, abs_tol     
		); 
		// 使用 std::cout 打印每個變量的解,以便在控制臺上查看結(jié)果。
        std::cout << "x[" << i << "] = " << solution.x[i] << std::endl;
	}

	return ok;
}

// main program that runs all the tests
int main(void)
{	
    std::cout << "===== Ipopt with CppAD Testing =====" << std::endl;
    bool result = get_started();
    std::cout << "Final checking: " << result << std::endl;
}
// END C++

?? 三、編譯驗證

?? 將上面第二部分,第6步中給出的完整的程序,保存為CppAD_Ipopt.cpp,然后在同一目錄下,創(chuàng)建一個名為CMakeLists.txt的文件,接下來,我們需要在CMakeLists.txt文件中,編寫編譯規(guī)則,如下所示:

# 設(shè)置CMake的最低版本要求
cmake_minimum_required(VERSION 3.5)
# 項目名稱
project(CppadIpoptDemo)
# 尋找Ipopt包(確保你已經(jīng)安裝了Ipopt和CppAD)
# find_package(Ipopt REQUIRED)
# 設(shè)置可執(zhí)行文件的名稱和源文件
add_executable(cppad_ipopt_demo CppAD_Ipopt.cpp)
# 包含Ipopt的頭文件
# target_include_directories(cppad_ipopt_demo PRIVATE ${IPOPT_INCLUDE_DIRS})
# 鏈接Ipopt庫
# target_link_libraries(cppad_ipopt_demo ${IPOPT_LIBRARIES})
TARGET_LINK_LIBRARIES(cppad_ipopt_demo ipopt)

?? 保存,并關(guān)掉CMakeLists.txt文件,接下來就利用該文件對CppAD_Ipopt.cpp進行編譯,在該目錄下空白處,右鍵打開終端,依次輸入以下四條語句

mkdir build
cd build
cmake ..
make
詳細介紹如何使用Ipopt非線性求解器求解帶約束的最優(yōu)化問題,Ubuntu和ROS,數(shù)值優(yōu)化方法,ipopt,數(shù)值優(yōu)化,最優(yōu)化方法,非線性求解器,Ubuntu,c++,Cppad

?? 以上編譯結(jié)束后,在build文件夾下,生成了可執(zhí)行文件cppad_ipopt_demo,如下圖所示

詳細介紹如何使用Ipopt非線性求解器求解帶約束的最優(yōu)化問題,Ubuntu和ROS,數(shù)值優(yōu)化方法,ipopt,數(shù)值優(yōu)化,最優(yōu)化方法,非線性求解器,Ubuntu,c++,Cppad

?? 在當前目錄下,右鍵打開終端,輸入以下指令運行該文件

./cppad_ipopt_demo

?? 運行結(jié)果如下,可以發(fā)現(xiàn)即使在給定的初始解很差的情況下,Ipopt非線性求解器依然能夠求解出第二部分第0部步中設(shè)定的帶約束優(yōu)化問題的最優(yōu)解。文章來源地址http://www.zghlxwxcb.cn/news/detail-721600.html

詳細介紹如何使用Ipopt非線性求解器求解帶約束的最優(yōu)化問題,Ubuntu和ROS,數(shù)值優(yōu)化方法,ipopt,數(shù)值優(yōu)化,最優(yōu)化方法,非線性求解器,Ubuntu,c++,Cppad

到了這里,關(guān)于詳細介紹如何使用Ipopt非線性求解器求解帶約束的最優(yōu)化問題的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包