Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

添加有约束多维最优化求解,和非线性最小二乘求解,并完善文档 #93

Merged
merged 1 commit into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions cmake/check/cxx23.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ struct S
{
int a{};

void f(this S self, int i)
{
self.a = i;
}
void f(this S self, int i) { self.a = i; }
};

// 打印库
Expand Down
33 changes: 31 additions & 2 deletions doc/doxygen-awesome.css
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,18 @@ div.contents div.dyncontent {
margin: var(--spacing-medium) 0;
}

@media (prefers-color-scheme: dark) {
html:not(.light-mode) div.contents div.dyncontent img,
html:not(.light-mode) div.contents center img,
html:not(.light-mode) div.contents > table img,
html:not(.light-mode) div.contents div.dyncontent iframe,
html:not(.light-mode) div.contents center iframe,
html:not(.light-mode) div.contents table iframe,
html:not(.light-mode) div.contents .dotgraph iframe {
filter: brightness(89%) hue-rotate(180deg) invert();
}
}

html.dark-mode div.contents div.dyncontent img,
html.dark-mode div.contents center img,
html.dark-mode div.contents > table img,
Expand Down Expand Up @@ -1034,7 +1046,7 @@ blockquote::after {
blockquote p {
margin: var(--spacing-small) 0 var(--spacing-medium) 0;
}
.paramname {
.paramname, .paramname em {
font-weight: 600;
color: var(--primary-dark-color);
}
Expand Down Expand Up @@ -1084,7 +1096,7 @@ div.contents .toc {
border: 0;
border-left: 1px solid var(--separator-color);
border-radius: 0;
background-color: var(--side-nav-background);
background-color: var(--page-background-color);
box-shadow: none;
position: sticky;
top: var(--toc-sticky-top);
Expand Down Expand Up @@ -1467,6 +1479,23 @@ h2.memtitle {
border-top-left-radius: var(--border-radius-medium);
border-top-right-radius: var(--border-radius-medium);
word-break: break-all;
position: relative;
}

h2.memtitle:after {
content: "";
display: block;
background: var(--fragment-background);
height: var(--spacing-medium);
bottom: calc(0px - var(--spacing-medium));
left: 0;
right: -14px;
position: absolute;
border-top-right-radius: var(--border-radius-medium);
}

h2.memtitle > span.permalink {
font-size: inherit;
}

h2.memtitle > span.permalink > a {
Expand Down
Binary file added doc/img/fminbnd/forward.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/fminbnd/principle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/fminbnd/region_reduce.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed doc/img/fminbnd_forward.png
Binary file not shown.
Binary file removed doc/img/fminbnd_forward_2.png
Binary file not shown.
Binary file removed doc/img/fminbnd_principle.png
Binary file not shown.
Binary file added doc/img/fminunc/fig1-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/fminunc/fig2-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/fminunc/fig2-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed doc/img/ls-eg1.png
Binary file not shown.
Binary file removed doc/img/ls-eg2.png
Binary file not shown.
Binary file removed doc/img/ls-eg3.png
Binary file not shown.
Binary file removed doc/img/ls-equations.png
Binary file not shown.
Binary file removed doc/img/ls-line-vertical.png
Binary file not shown.
Binary file removed doc/img/ls-vector-vertical.png
Binary file not shown.
Binary file added doc/img/lsq/eg1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/lsq/eg2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/lsq/eg3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/lsq/equations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/lsq/line-vertical.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/lsq/vector-vertical.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed doc/img/region_reduce.png
Binary file not shown.
12 changes: 9 additions & 3 deletions doc/intro.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,18 @@ RMVL 具有模块化结构,这意味着该软件包包含了多个共享或静
- @ref core (**core**) —— 包含主要的工具库、数据读写、宏定义、版本管理等内容,以及 rm::Exception 异常管理模块就在此处定义。

- @ref camera (**camera**) —— 目前包含 3 种相机厂商 SDK 的二次开发工具库,具体可参考下表。

<center>

表 1: 相机厂商 SDK 二次开发工具库<br>
| 厂商 | 简称 |
| :-------------------: | :--: |
| 奥普特机器视觉 | OPT |
| 海康机器人 *HIKROBOT* | Hik |
| 迈德威视 *Mindvision* | Mv |

</center>

点击[此处](@ref tutorial_install)可以安装以上相机的 SDK

- @ref ml (**ml**), @ref opcua (**opcua**)
Expand All @@ -61,9 +67,9 @@ RMVL 具有模块化结构,这意味着该软件包包含了多个共享或静
#### 功能模块 {#function_modules}

- @ref detector (**detector**) —— 识别、检测器是功能模块中最重要的部分,也是视觉图像处理的第一步。它负责对输入图像进行识别并加以处理,提取出目标轮廓、特征点等信息,并结合已知的部分数据组件,按顺序依次构建各种新的数据组件。
<center>
<img src="https://s1.ax1x.com/2022/11/05/xOgdat.md.png" alt="xOgdat.png" border="0" />
</center>

<img src="https://s1.ax1x.com/2022/11/05/xOgdat.md.png" alt="xOgdat.png" border="0" />

识别得到的各种图像以及提取到的特征和组合体均保存至识别模块信息 `rm::DetectInfo` 中。

- @ref compensator (**compensator**) —— 补偿器通常是功能模块中的第一个用于修正数据组件的算法模块,<span style="color: green">主要在 RoboMaster 赛事中使用</span>。补偿器主要负责修正弹道下坠的影响。计算得到的子弹飞行时间 `tof` 以及补偿增量 `compensation` 均保存至补偿模块信息 `rm::CompensateInfo` 中。
Expand Down
22 changes: 14 additions & 8 deletions doc/tutorials/extra/combo/how_to_use.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,20 @@ auto p_combo = make_combo(p_left, p_right, gyro_data, tick);

#### 1.2.1 数据信息

`combo` 记录了空间上彼此关联的一组 `feature`,内部使用 `vector<feature::ptr>` 表示。`combo` 提供了与序列式容器类似的访问操作,包括

| 信息获取接口 | 实现功能 |
| :----------: | :------------------------------------------: |
| `at(idx)` | 获取指定的下表`idx` |
| `data()` | 获取`vector<feature::ptr>`(特征列表)的数据 |
| `size()` | 获取特征列表的大小 |
| `empty()` | 判断特征列表是否为空 |
`combo` 记录了空间上彼此关联的一组 `feature`,内部使用 `std::vector<feature::ptr>` 表示。`combo` 提供了与序列式容器类似的访问操作,包括

<center>

表 1: combo 信息获取接口

| 信息获取接口 | 实现功能 |
| :----------: | :-----------------------------------------------: |
| `at(idx)` | 获取指定的下表`idx` |
| `data()` | 获取`std::vector<feature::ptr>`(特征列表)的数据 |
| `size()` | 获取特征列表的大小 |
| `empty()` | 判断特征列表是否为空 |

</center>

#### 1.2.2 通用属性与派生类属性

Expand Down
13 changes: 6 additions & 7 deletions doc/tutorials/extra/upper/upper_base.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,16 @@

以下为 RMVL 顶层模块大致要具备的功能,以流程图形式展现

![upper-base](upper_base.png)
<center>

![图 1 顶层模块流程图](upper_base.png)

</center>

**注意:**

- 这里下位机一般指控制端,平台不固定,可以是嵌入式设备,例如 STM32 系列单片机,也可以是基于 ROS 的 ros-control 控制层
- 程序处理部分
| 符号 | 含义 |
| :---: | :------------: |
| `i` | 传入参数 |
| `io` | 传入兼传出参数 |
| `ret` | 函数返回值 |
- 程序处理部分 \f[\begin{array}{c|c}符号&含义\\\hline \text{i}&传入参数\\\text{io}&传入兼传出参数\\\text{ret}&函数返回值\end{array}\f]
- 流程图中给出了 4 个程序处理的基本顺序,实际上可以根据具体的逻辑需求选择使用其中的一种或多种程序处理模块,这些程序处理模块则刚好对应于 4 个 **功能模块** 。

------
Expand Down
6 changes: 5 additions & 1 deletion doc/tutorials/extra/upper/upper_process.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,11 @@ FeatureHandler: Handling the feature request.

因此,常规用法中的<span style="color: red">请求</span>在 RMVL 功能模块中表示为<span style="color: red">数据组件</span>,各功能模块的返回值 `XxxInfo` 则可以作为下一个功能模块的入参。可以继续参考此流程图

![upper-base](upper_base.png)
<center>

![图 1 顶层模块流程图](upper_base.png)

</center>

程序处理III(预测)的入参包含了补偿模块的返回值信息 `rm::CompensateInfo`,程序处理IV(决策)的入参包含了前 3 个模块的返回值 `rm::DetectInfo`、`rm::CompensateInfo`、`rm::PredictInfo`。

Expand Down
14 changes: 6 additions & 8 deletions doc/tutorials/modules/algorithm/fminbnd.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,13 @@

<center>

![图 1-1 向前一步](fminbnd_forward.png)

![图 1-2 向前两步](fminbnd_forward_2.png)
![图 1 进退法](fminbnd/forward.png)

</center>

1. 选择一个初始点\f$\alpha_1\f$和一个初始步长\f$h\f$。
2. 如图 1-1 所示,计算点\f$\alpha_1\f$和点\f$\alpha_1+h\f$对应的函数值\f$f(\alpha_1)\f$和\f$f(\alpha_1+h)\f$,令\f[f_1=f(\alpha_1),\quad f_2=f(\alpha_1+h)\f]
3. 比较\f$f_1\f$和\f$f_2\f$,若\f$f_1>f_2\f$,则执行前进运算,将步长加大\f$k\f$倍(如加大 2 倍),取新点\f$\alpha_1+3h\f$,如图 1-2 所示,计算其函数值,并令\f[f_1=f(\alpha_1+h),\quad f_2=f(\alpha_1+3h)\f]若\f$f_1< f_2\f$,则初始搜索区间端点为\f[a=\alpha_1,\quad b=\alpha_1+3h\f]若\f$f_1=f_2\f$,则初始搜索区间端点为\f[a=\alpha_1+h,\quad b=\alpha_1+3h\f]若\f$f_1>f_2\f$,则要继续做前进运算,且步长再加大两倍,取第 4 个点\f$\alpha_1+7h\f$,再比较第 3 和第 4 个点处的函数值……如此反复循环,直到在连续的 3 个点的函数值出现“两头大、中间小”的情况为止。
2. 如图 1(a) 所示,计算点\f$\alpha_1\f$和点\f$\alpha_1+h\f$对应的函数值\f$f(\alpha_1)\f$和\f$f(\alpha_1+h)\f$,令\f[f_1=f(\alpha_1),\quad f_2=f(\alpha_1+h)\f]
3. 比较\f$f_1\f$和\f$f_2\f$,若\f$f_1>f_2\f$,则执行前进运算,将步长加大\f$k\f$倍(如加大 2 倍),取新点\f$\alpha_1+3h\f$,如图 1(b) 所示,计算其函数值,并令\f[f_1=f(\alpha_1+h),\quad f_2=f(\alpha_1+3h)\f]若\f$f_1< f_2\f$,则初始搜索区间端点为\f[a=\alpha_1,\quad b=\alpha_1+3h\f]若\f$f_1=f_2\f$,则初始搜索区间端点为\f[a=\alpha_1+h,\quad b=\alpha_1+3h\f]若\f$f_1>f_2\f$,则要继续做前进运算,且步长再加大两倍,取第 4 个点\f$\alpha_1+7h\f$,再比较第 3 和第 4 个点处的函数值……如此反复循环,直到在连续的 3 个点的函数值出现“两头大、中间小”的情况为止。
4. 如果在 **步骤 3** 中出现\f$f_1< f_2\f$的情况,则执行后退运算,将步长变为负值,取新点\f$\alpha_1-h\f$,计算函数值,令\f[f_1=f(\alpha_1-h),\quad f_2=f(\alpha_1)\f]若\f$f_1>f_2\f$,则初始搜索区间端点为\f[a=\alpha_1-h,\quad b=\alpha_1+h\f]若\f$f_1=f_2\f$,则初始搜索区间端点为\f[a=\alpha_1-h,\quad b=\alpha_1\f]若\f$f_1< f_2\f$,则要继续做后退运算,且步长再加大两倍,取第 4 个点\f$\alpha_1-3h\f$,再比较第 3 和第 4 个点处的函数值……如此反复循环,直到在连续的 3 个点的函数值出现“两头大、中间小”的情况为止。

<span style="color: green">**示例**</span>
Expand All @@ -61,15 +59,15 @@

黄金分割法是利用区间消去法的原理,通过不断缩小单峰区间长度,即每次迭代都消去一部分不含极小值点的区间,使搜索区间不断缩小,从而逐渐逼近目标函数极小值点的一种优化方法。黄金分割法是直接寻优法,通过直接比较区间上点的函数值的大小来判断区间的取舍。这种方法具有计算简单、收敛速度快等优点。

如图1-2所示,在已确定的单峰区间[a,b]内任取\f$\alpha_1\f$,\f$\alpha_2\f$两点,计算并比较两点处的函数值\f$f(\alpha_1)\f$和\f$f(\alpha_2)\f$,可能出现3种情况:
如图 1(b) 所示,在已确定的单峰区间[a,b]内任取\f$\alpha_1\f$,\f$\alpha_2\f$两点,计算并比较两点处的函数值\f$f(\alpha_1)\f$和\f$f(\alpha_2)\f$,可能出现3种情况:

1. \f$f(\alpha_1)< f(\alpha_2)\f$,因为函数是单峰的,所以极小值点必定位于点\f$\alpha_2\f$的左侧,即\f$\alpha^*\in[a,\alpha_2]\f$,搜索区间可以缩小为\f$[a,\alpha_2]\f$,如图 2-1(a) 所示;
2. \f$f(\alpha_1)>f(\alpha_2)\f$,极小值点必定位于点\f$\alpha_1\f$的右侧,即\f$\alpha^*\in[\alpha_1,b]\f$,搜索区间可以缩小为\f$[\alpha_1,b]\f$,如图 2-1(b) 所示;
3. \f$f(\alpha_1)=f(\alpha_2)\f$,极小值点必定位于点\f$\alpha_1\f$和\f$\alpha_2\f$之间,即\f$\alpha^*\in[\alpha_1,\alpha_2]\f$,搜索区间可缩小为\f$[\alpha_1,\alpha_2]\f$,如图 2-1(c) 所示。

<center>

![图 2-1 搜索区间缩小示意图](region_reduce.png)
![图 2-1 搜索区间缩小示意图](fminbnd/region_reduce.png)

</center>

Expand All @@ -92,7 +90,7 @@

<center>

![图 2-2 黄金分割法原理](fminbnd_principle.png)
![图 2-2 黄金分割法原理](fminbnd/principle.png)

</center>

Expand Down
128 changes: 126 additions & 2 deletions doc/tutorials/modules/algorithm/fminunc.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
@author 赵曦
@date 2024/05/06
@version 1.0
@brief 包含最速下降、共轭梯度、Nelder-Mead 单纯形法的介绍
@brief 包含最速下降、共轭梯度的介绍

@prev_tutorial{tutorial_modules_fminbnd}

Expand All @@ -14,4 +14,128 @@

------

@warning 未完成
\f[
\def\red#1{\color{red}{#1}}
\def\teal#1{\color{teal}{#1}}
\def\green#1{\color{green}{#1}}
\def\transparent#1{\color{transparent}{#1}}
\def\orange#1{\color{orange}{#1}}
\def\fml#1{\text{(#1)}}
\f]

### 1. 最速下降法

沿函数的负梯度方向,函数值下降最多,因此,对于存在导数的连续目标函数,最速下降法是一种简单而有效的优化方法。可以将目标函数的负梯度方向作为寻优方向,即

\f[\pmb s_k=-\frac{\nabla f(\pmb x_k)}{\|\nabla f(\pmb x_k)\|}\tag{1-1}\f]

因此当前点为 \f$\pmb x_k\f$ 时,下一个点的表达式为

\f[\pmb x_{k+1}=\pmb x_k+\alpha_k\pmb s_k=\pmb x_k-\alpha_k\frac{\nabla f(\pmb x_k)}{\|\nabla f(\pmb x_k)\|}\tag{1-2}\f]

对于每轮得到的一个新的负梯度方向,再利用 @ref tutorial_modules_fminbnd 求解 \f$\alpha_k\f$。最速下降法的迭代步骤如下:

1. 选取初始点 \f$\pmb x_0\f$,设置判断收敛的正数 \f$\epsilon\f$;
2. 令 \f$k=0\f$;
3. 计算 \f$-\nabla f(\pmb x_k)\f$;
4. 按 \f$\fml{1-2}\f$ 计算 \f$\pmb s_k\f$,若 \f$\|\pmb s_k\|<\epsilon\f$,则停止迭代,\f$\pmb x_k\f$ 为最优解,否则进行下一步;
5. 进行一维搜索,求解 \f$\alpha_k\f$,使 \f[f(\pmb x_k+\alpha_k\pmb s_k)=\min_{\alpha>0}f(\pmb x_k+\alpha\pmb s_k)\tag{1-3}\f]
6. 计算 \f$\pmb x_{k+1}=\pmb x_k+\alpha_k\pmb s_k\f$,令 \f$k=k+1\f$,返回第 3 步。

最速下降法对于一般的函数而言,在远离极值点时函数值下降得很快,最速下降法队椭圆类函数十分有效,可以很快搜索到接近极值点。但是当距离极值点较近时,特别是存在脊线的目标函数,收敛过程可能会十分缓慢,如图 1-1 所示。

<center>

![图 1-1 存在脊线的目标函数](fminunc/fig1-1.png)

</center>

### 2. 共轭梯度法

#### 2.1 共轭方向

同心椭圆族曲线的两平行切线有这样的特性:通过两平行线与椭圆的切点作连线,该直线通过该椭圆族的中心,如图 2-1 所示。因为该连线的方向与两平行线是共轭方向,所以利用这一特性寻优称为共轭方向法。

<center>

![图 2-1 平行的同心椭圆族的切点连线过其中心](fminunc/fig2-1.png)

</center>

如果有一组 \f$n\f$ 个非零向量组 \f$\pmb s_1,\pmb s_2,\dots,\pmb s_n\in\pmb E^n\f$,且这个向量组中的任意两个向量关于 \f$n\f$ 阶实对称正定矩阵 \f$\pmb A\f$ 满足式 \f[\pmb s_i^T\pmb A\pmb s_j=0,\quad i,j=1,2,\dots,n\ 且\ i\ne j\tag{2-1}\f] 则称

- 向量组 \f$\pmb s_1,\pmb s_2,\dots,\pmb s_n\f$ 是关于矩阵 \f$\pmb A\f$ 共轭的;
- \f$\pmb s_i\f$ 和 \f$\pmb s_j\f$ 是实对称正定矩阵 \f$\pmb A\f$ 的共轭方向。

有这一个特殊情况,当矩阵 \f$\pmb A\f$ 是单位矩阵时,向量的共轭就相当于向量的正交。共轭方向相当于将原来的非正椭圆函数通过矩阵 \f$\pmb A\f$ 变换为正圆函数,而共轭方向 \f$\pmb s_1\f$ 和 \f$\pmb s_2\f$ 则是变换后的垂直方向 \f$\pmb p_1\f$ 和 \f$\pmb p_2\f$,如图 2-2 所示。

<center>

![图 2-2 共轭与正交对比](fminunc/fig2-2.png)

</center>

#### 2.2 共轭梯度方向的构造

在极值点 \f$x^*\f$ 附近,目标函数可以近似为二次型函数,即 \f[f(\pmb x)\approx c+\pmb b^T\pmb x+\frac12\pmb x^T\pmb A\pmb x\tag{2-2}\f]

1. 从 \f$\pmb x_k\f$ 点出发,沿负梯度 \f$\pmb s_k=-\nabla f(\pmb x_k)\f$ 方向寻优,得到新优化点 \f$\pmb x_{k+1}\f$。再按下式构造与 \f$\pmb s_k\f$ 共轭的方向 \f$\pmb s_{k+1}\f$:\f[\pmb s_{k+1}=-\nabla f(\pmb x_{k+1})+\beta_k\pmb s_k\tag{2-3}\f] 在公式 \f$\fml{2-3}\f$ 中,\f$\beta_k\f$ 按下式计算时,可满足共轭条件 \f$\pmb s_{k+1}^T\pmb A\pmb s_k=0\f$:\f[\beta_k=\frac{\|\nabla f(\pmb x_{k+1})\|^2}{\|\nabla f(\pmb x_k)\|^2}\tag{2-4}\f]
2. 沿着 \f$\pmb s_{k+1}\f$ 方向寻优,直至求出极值 \f$\pmb x^*\f$。

上面只是对目标函数为二次型函数的情况求得了构成共轭方向的系数 \f$\beta_k\f$,对于一般的目标函数,有 \f[\beta_k=\frac{\|\nabla f(\pmb x_{k+1})\|^2-[\nabla f(\pmb x_{k+1})]^T\nabla f(\pmb x_k)}{\|\nabla f(\pmb x_k)\|^2}\tag{2-5}\f]

从而类似式 \f$\fml{2-3}\f$ 有 \f[\pmb s_{k+1}=-\nabla f(\pmb x_{k+1})+\beta_k\pmb s_k\f]

#### 2.3 迭代步骤

1. 选取初始点 \f$\pmb x_0\f$,设置判断收敛的正数 \f$\epsilon\f$;
2. 令 \f$k=0\f$,\f$\pmb s_0=-\nabla f(\pmb x_0)\f$;
3. 进行一维搜索,求解 \f$\alpha_k\f$,使 \f$f(\pmb x_k+\alpha_k\pmb s_k)=\min_{\alpha>0}f(\pmb x_k+\alpha\pmb s_k)\f$
4. 计算 \f$\nabla f(\pmb x_{k+1})\f$,并令 \f$\pmb x_{k+1}=\pmb x_k+\alpha_k\pmb s_k\f$;
5. 若 \f$\|\nabla f(\pmb x_{k+1})\|<\epsilon\f$,则停止迭代,\f$\pmb x_{k+1}\f$ 为最优解,否则按 \f$\fml{2-5}\f$ 计算 \f$\beta_k\f$,令 \f[\pmb s_{k+1}=-\nabla f(\pmb x_{k+1})+\beta_k\pmb s_k\f]
6. 令 \f$k=k+1\f$,返回第 3 步。

#### 2.4 如何使用

首先定义一个目标函数,例如:

```cpp
static inline double quadratic(const std::vector<double> &x)
{
const auto &x1 = x[0], &x2 = x[1];
return 60 - 10 * x1 - 4 * x2 + x1 * x1 + x2 * x2 - x1 * x2;
}
```

然后调用 `rm::fminunc` 函数:

```cpp
auto [x, fval] = rm::fminunc(quadratic, {0, 0});
```

汇总起来,共轭梯度法的使用实例如下:

```cpp
#include <cstdio>

#include <rmvl/numcal.hpp>

int main()
{
// 定义二次函数
auto quadratic = [](const std::vector<double> &x) {
const auto &x1 = x[0], &x2 = x[1];
return 60 - 10 * x1 - 4 * x2 + x1 * x1 + x2 * x2 - x1 * x2;
};

// 求解无约束多维最优化问题,默认使用共轭梯度法
auto [x, fval] = rm::fminunc(quadratic, {0, 0});
printf("min[f(x,y)] = f(%f, %f) = %f\n", x[0], x[1], fval);
}
```

运行结果如下:

```
min[f(x,y)] = f(8.0000, 6.0000) = 8.0000
```
2 changes: 1 addition & 1 deletion doc/tutorials/modules/algorithm/func_iteration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
@version 1.0
@brief 涉及 **不动点迭代** 与 **牛顿迭代** 两种非线性方程组数值解的求法

@prev_tutorial{tutorial_modules_least_square}
@prev_tutorial{tutorial_modules_lsqnonlin}

@next_tutorial{tutorial_modules_runge_kutta}

Expand Down
8 changes: 2 additions & 6 deletions doc/tutorials/modules/algorithm/interpolation.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ p(x_n)&=a_0+a_1x_n+a_2x_n^2+\cdots+a_{n-1}x_n^{n-1}=f(x_n)=y_n

使用以下节点进行二次插值

| \f$x\f$ | \f$1\f$ | \f$2\f$ | \f$3\f$ |
| :--------: | :-----: | :-----: | :-----: |
| \f$f(x)\f$ | \f$2\f$ | \f$1\f$ | \f$2\f$ |
\f[\begin{array}{c|ccc}x&1&2&3\\\hline f(x)&2&1&2\end{array}\f]

**解答**

Expand Down Expand Up @@ -107,9 +105,7 @@ a_2&=f\left[x_0,x_1,x_2\right]=\frac{f\left[x_0,x_1\right]-f\left[x_1,x_2\right]

使用以下节点进行 3 次插值

| \f$x\f$ | \f$0\f$ | \f$1\f$ | \f$2\f$ | \f$3\f$ |
| :--------: | :-----: | :-----: | :-----: | :-----: |
| \f$f(x)\f$ | \f$0\f$ | \f$1\f$ | \f$3\f$ | \f$2\f$ |
\f[\begin{array}{c|cccc}x&0&1&2&3\\\hline f(x)&0&1&3&2\end{array}\f]

**解答**

Expand Down
Loading
Loading