3-2 二次插值法
二次插值法
简述
\(\qquad\)在已经确定的搜索区间内进行一维搜索时,可以利用若干点处的函数值信息来构造低次插值多项式,用它作为函数的近似表达式,并用这个多项式的极小值点作为原函数极小值点的近似。常用的低次插值多项式为二次多项式。利用二次多项式所进行的插值法称为二次插值法。作为一种一维搜索的插值方法,二次插值法是求解一维搜索问题时常用的优化方法。
\(\qquad\)二次插值法又称抛物线法 。上一篇讲到的黄金分割法的计算次数是由初始区间长度与收敛精度决定的,因为其每一步的收缩比例确定0.618,而插值法则不同,不仅用到点及函数值信息,还利用到函数的解析信息。对于具有较好解析性的函数其收敛速度较快。
二次插值法原理
对于符合"大---小---大"条件的三点 \((x_1,y_1),\;(x_2,y_2),\;(x_3,y_3)\),即 \(x_1 < x_2 < x_3,\;\min{(y_1,y_2,y_3)}=y_2\),求二次插值多项式:
\p(x) = a_0 + a_1 x + a_2 x\^2 \\
以插值多项式 \(p(x)\) 的极小值点 \(x^*\) 近似函数的极值点:
\x\^\* = -\\frac{a_1}{2a_2} \\
将 \((x_1,y_1),\;(x_2,y_2),\;(x_3,y_3)\) 三点代入 \(p(x)\):
\\\left(\\begin{array}{ccc} 1 \& x_1 \& x_1\^2 \\\\ 1 \& x_2 \& x_2\^2 \\\\ 1 \& x_3 \& x_3\^2 \\end{array}\\right) \\left(\\begin{array}{c} a_0 \\\\ a_1 \\\\ a_2 \\end{array}\\right) = \\left(\\begin{array}{c} y_1 \\\\ y_2 \\\\ y_3 \\end{array}\\right) \\
可得 \(a_1,\;a_2\):
\\\begin{aligned} a_{1}\&=\\frac{\\left(x_{2}\^{2}-x_{3}\^{2}\\right)y_{1}+\\left(x_{3}\^{2}-x_{1}\^{2}\\right)y_{2}+\\left(x_{1}\^{2}-x_{2}\^{2}\\right)y_{3}}{\\left(x_{1}-x_{2}\\right)\\left(x_{2}-x_{3}\\right)\\left(x_{3}-x_{1}\\right)}\\\\ a_{2}\&=-\\frac{\\left(x_{2}-x_{3}\\right)y_{1}+\\left(x_{3}-x_{1}\\right)y_{2}+\\left(x_{1}-x_{2}\\right)y_{3}}{\\left(x_{1}-x_{2}\\right)\\left(x_{2}-x_{3}\\right)\\left(x_{3}-x_{1}\\right)} \\end{aligned} \\
最终求出极小点:
\x\^{\*}=-{\\frac{1}{2}}{\\frac{(x_{2}\^{\~2}-x_{3}\^{\~2})y_{1}+(x_{3}\^{\~2}-x_{1}\^{\~2})y_{2}+(x_{1}\^{\~2}-x_{2}\^{\~2})y_{3}}{(x_{2}-x_{3})y_{1}+(x_{3}-x_{1})y_{2}+(x_{1}-x_{2})y_{3}}} \\
\(\qquad\)通过二次曲线对原目标函数的近似表达,得到区间 \(x_1,\\;x_3\) 之间的插值多项式的极小点 \(x^*\),将 \(x^*\) 与 \(x_2\) 作为该区间中的比较点,比较函数值 \(y^*\) 与 \(y_2\) 大小便可按区间消去法舍弃部分区间。重复上述过程,直至区间长度缩减至满足精度要求。
\(\qquad\)当原目标函数解析性较好(即与二次抛物曲线相似度较高)时,二次插值法收敛速度较快。
由于二次插值法是采用二次多项式来近似表达原函数,因此该方法不适用于求解二次函数的极值点。
具体步骤
对于给定区间 \(x_1,\\;x_3\) 和精度 \(\varepsilon\):
-
① 先求出 \(x_2 = \frac{x_1 + x_3}{2}\),再依次求出 \(y_1,\;y_2,\;y_3,\;x^*\) 和 \(y^*\);
-
② 若 \(x^* < x_2,\;y^* < y_2\),区间缩小为 \(x_1,x\^\*,x_2\);
\(\quad\)若 \(x^* < x_2,\;y^* \ge y_2\),区间缩小为 \(x\^\*,x_2,x_3\);
\(\quad\)若 \(x_2 < x^*,\;y^* < y_2\),区间缩小为 \(x_2,x\^\*,x_3\);
\(\quad\)若 \(x_2 < x^*,\;y^* \ge y_2\),区间缩小为 \(x_1,x_2,x\^\*\);
-
③ 不断重复缩小区间,直到:\(|x^* - x_2|< \varepsilon\),取最小值为 \(y\) 值更小的那个 \(x\)。
第二步骤的缩小区间,简而言之:\(x^*\) 和 \(x_2\) 相邻,y 值更小的 x 放中间,作为新区间的 x。
如下图所示,为二次插值法的迭代过程示意图,图中 \(\alpha_1,\;\alpha_2,\;\alpha_3,\;\alpha_p^*\) 分别对应本文中的 \(x_1,\;x_2,\;x_3,\;x^*\),图中 \(\alpha^*\) 为原函数的实际极小值点。

流程框图

代码示例
对于二次插值法,给出以下C++函数仅供参考。
C++代码示例:
cpp
// 二次插值法 求最小值点(横坐标)
double quadratic_interpolation(function<double(double)> func, double l, double r, double eps) {
double x1 = l, x3 = r;
double x2 = (x1 + x3) / 2.0;
double y1 = func(x1), y2 = func(x2), y3 = func(x3);
int step = 0;
printf("[debug] step %d: x1=%.5lf, x2=%.5lf, x3=%.5lf\n", step, x1, x2, x3);
while (true) {
// 根据公式计算插值多项式的极小点 x*
double num = (x2*x2 - x3*x3)*y1 + (x3*x3 - x1*x1)*y2 + (x1*x1 - x2*x2)*y3;
double den = (x2 - x3)*y1 + (x3 - x1)*y2 + (x1 - x2)*y3;
// 防止分母为0导致除零错误
if (abs(den) < 1e-9) {
break;
}
double xp = -0.5 * num / den;
double yp = func(xp);
// 判断终止条件:|x* - x2| < eps
if (abs(xp - x2) < eps) {
// 取 y 值更小的那个 x
return (yp < y2) ? xp : x2;
}
// 缩小区间
if (xp < x2) {
if (yp < y2) {
// 若 x* < x2, y* < y2,区间缩小为 [x1, x*, x2]
x3 = x2; y3 = y2;
x2 = xp; y2 = yp;
} else {
// 若 x* < x2, y* >= y2,区间缩小为 [x*, x2, x3]
x1 = xp; y1 = yp;
}
} else {
if (yp < y2) {
// 若 x2 < x*, y* < y2,区间缩小为 [x2, x*, x3]
x1 = x2; y1 = y2;
x2 = xp; y2 = yp;
} else {
// 若 x2 < x*, y* >= y2,区间缩小为 [x1, x2, x*]
x3 = xp; y3 = yp;
}
}
step++;
printf("[debug] step %d: x1=%.5lf, x2=%.5lf, x3=%.5lf\n", step, x1, x2, x3);
}
// 兜底返回当前三点中 y 值最小的 x
if (y1 <= y2 && y1 <= y3) return x1;
if (y2 <= y3) return x2;
return x3;
}
本学习笔记参考资料:
1 白清顺, 孙靖民, 梁迎春. 机械优化设计 第7版M. 北京: 机械工业出版社, 2024. ISBN: 978-7-111-75103-8 在线链接
2 武汉理工大学《最优化技术B》课程课件,授课教师:颜彬老师