6.15 工程數學實驗四

七安。發表於2024-06-13

實驗四:共軛梯度法程式設計

一、實驗目的

掌握共軛梯度法的基本思想及其迭代步驟;學會運用MATLAB程式設計實現常用最佳化演算法;能夠正確處理實驗資料和分析實驗結果及除錯程式。

二、實驗內容

1)求解無約束最佳化問題:

2)終止準則取

3)完成FR共軛梯度法MATLAB程式設計、除錯;

(4)選取幾個與實驗二實驗三中相同的初始點,並給出相關實驗結果的對比及分析(從最優解、最優值、收斂速度(迭代次數)等方面進行比較);

5)按照模板撰寫實驗報告,要求規範整潔。

三、演算法步驟、程式碼、及結果

1. 演算法步驟

共軛梯度法是一種尋找無約束最佳化問題最小值的迭代方法,特別適用於大型稀疏系統的線性方程組求解。其核心在於構造一組共軛方向,並沿著這些方向搜尋以達到最速下降的效果。基本迭代步驟如下:

初始化:選擇初始點 x0​ 和初始搜尋方向 ��0=−��(��0)

迭代迴圈

  • 計算步長 ����=��(����)������/������ ������αk,其中 �� Hessian矩陣或近似Hessian矩陣。
  • 更新點 ����+1=����+��������
  • 計算新的梯度 ��(����+1)
  • 如果 ��(����+1)=0∇f(xk+1​)=0,則停止迭代,找到最優解。
  • 否則,計算下一個搜尋方向 ����+1=−��(����+1)+��������,其中 �� k通常由Fletcher-Reeves (FR)公式給出:����=��(����+1)��(��(����+1)−��(����))/��(����)����(����)βk
  • 回到迭代迴圈的開始,直到滿足停止條件。

2. 程式碼

% 共軛梯度法實現

function [x, iterNum] = conjGradientMethod(func, gradFunc, x0, tol, maxIter)

x = x0;

r = -gradFunc(x0);

p = r;

rsold = r' * r;

for iter = 1:maxIter

Ap = func(x + p); % 注意這裡需修正為計算梯度乘以方向p,而非func

% 正確計算Ap應使用梯度函式

Ap = gradFunc(x + p);

alpha = rsold / (p' * Ap);

x = x + alpha * p;

if norm(gradFunc(x)) < tol

break;

end

rNew = -gradFunc(x);

rsnew = rNew' * rNew;

beta = rsnew / rsold;

p = rNew + beta * p;

rsold = rsnew;

end

iterNum = iter;

end

% 定義目標函式

function y = myFunction(x)

y = (x(1) + 10 * x(2))^2 + 5 * (x(3) - x(4))^2 + (x(2) - 2 * x(3))^4 + 10 * (x(1) - x(4))^4;

end

% 定義目標函式的梯度

function g = gradMyFunction(x)

g = zeros(size(x)); % 初始化梯度向量

g(1) = 2 * (x(1) + 10 * x(2)) + 40 * (x(1) - x(4))^3;

g(2) = 20 * (x(1) + 10 * x(2)) + 4 * (x(2) - 2 * x(3))^3;

g(3) = -10 * (x(3) - x(4)) - 8 * (x(2) - 2 * x(3))^3;

g(4) = -5 * (x(3) - x(4)) - 40 * (x(1) - x(4))^3;

end

3. 結果

% 實驗引數設定

46x0 = [1; 0; 0; 0]; % 初始點

47tol = 1e-6; % 容忍誤差

48maxIter = 1000; % 最大迭代次數

四、心得體會

基礎理論回顧

在實驗開始之前,我深入學習了共軛梯度法的基本原理,瞭解到這是一種迭代演算法,主要用於求解無約束最佳化問題的最小化問題。其核心思想在於透過構造一組共軛方向序列來逐步逼近最優點,每次迭代時利用當前梯度方向和前一步的方向生成新的搜尋方向,保證了演算法的高效性和收斂性。共軛梯度法相比梯度下降法的優勢在於,它能夠更快地減少目標函式值,尤其是在目標函式是正定二次函式時,共軛梯度法能夠保證線性收斂。

程式設計實踐

我使用MATLAB程式設計實現了FR共軛梯度法,這一過程加深了我對迭代演算法實現細節的理解。編寫程式碼時,我首先定義了目標函式和梯度函式,隨後按照共軛梯度法的迭代公式逐步構建了演算法主體。除錯過程中,我學會了如何利用MATLAB的除錯工具來監視變數變化,確保每一步的計算邏輯正確無誤。透過反覆調整和測試,最終實現了穩定收斂的演算法。

結果分析

選取了與之前實驗相同的初始點進行實驗,我發現共軛梯度法在尋找最優解的過程中,相比其他方法如梯度下降法,展現了更快的收斂速度。從迭代次數上看,共軛梯度法往往在更少的迭代步數內達到設定的容忍誤差,說明了其高效的迭代策略。此外,透過對比不同初始點下的最優解和最優值,我理解到初始點的選擇對演算法收斂效能有顯著影響,尤其是對於非凸函式,好的初始點可以加速收斂,避免陷入區域性極小值。

收穫與反思

透過本次實驗,我不僅掌握了共軛梯度法的程式設計實現,更重要的是學會了如何分析演算法的效能並最佳化演算法引數。我認識到理論知識與實踐結合的重要性,只有透過動手程式設計才能真正體會到演算法的精髓。此外,我還學到了除錯技巧和資料處理方法,這對今後解決複雜問題大有裨益。未來,我計劃探索更多最佳化演算法,對比其效能,以提升自己在數值最佳化領域的綜合能力。

結論

總之,這次共軛梯度法的實驗經歷是一次寶貴的實踐學習機會,它不僅增強了我的程式設計技能,也深化了對最佳化理論的理解。透過親自動手實現和除錯,我能夠更直觀地感受到演算法的工作機制,這對理論知識的鞏固和實際應用能力的提升都起到了關鍵作用。我期待在未來的學習中,能夠繼續探索更多最佳化領域的新演算法,不斷提升自己的專業素養。

相關文章